<hr>
<<receive>>Hey, how's it going sport?<</receive>>
<<send>>It's going great, dad.<</send>>
<<send>>Thanks for asking<</send>>
<<receive>>Anytime, slugger<</receive>>
<<tfinish>><hr>
<<send>>Hey, dad, how's it goin?<</send>>
<<receive>>It's going well, sport!<</receive>>
<<receive>>Thanks for asking.<</receive>>
<<send>>No problem, pops.<</send>>
<<tfinish>><hr>
<<receive>>Heya, I'm just popping in to help with the live receive demo, pal<</receive>>
<<send>>You've done a great job! A notification appeared in the phone's header and there was an alert beside your name until I opened up the chat.<</send>>
<<receive>>That's dope<</receive>>
<<tfinish>><hr>
<<send>>Hey Dad, I just wanted to get your help with the send chat demo!<</send>>
<<receive>>Sure, I'd love to help!<</receive>>
<<send>>Great, that's actually all the help I need. No notifications appeared or anything since I'm the one who started this chat. Your name did glow before I started talking to you, though<</send>>
<<receive>>Woah, cool<</receive>>
<<tfinish>><hr>
<<receive>>Hey, how's it going, sport<</receive>>
<<textchoice "Havin' a bad time, pops" "Branching Bad">><<set $dadLove = 1>><</textchoice>>
<<tchoice "It's going great, dad" "Branching Good">><<send>>Havin' a bad time, pops<</send>>
<<receive>>Aw, that's a bummer<</receive>>
<<send>>C'est la vie<</send>>
<<tfinish>><<send>>It's going great, dad<</send>>
<<receive>>I'm glad to hear that!<</receive>>
<<tfinish>><hr>
<<receive>>Hey, this is the chat for link #1.<</receive>>
<<if sp.chatIgnored() is true>>
<<receive>>I see you ignored me by clicking link #2 after me :(<</receive>>
<<else>>
<<receive>>I'm glad you didn't ignore me!!<</receive>>
<</if>>
<<tfinish>><hr>
<<receive>>Hey, this is the chat for link #2.<</receive>>
<<if sp.chatIgnored() is true>>
<<receive>>I see you ignored me by clicking link #1 after me :(<</receive>>
<<else>>
<<receive>>I'm glad you didn't ignore me!!<</receive>>
<</if>>
<<tfinish>><hr>
<<receive>>Hey, which choice are you going to make?<</receive>>
<<textchoice "I'm picking the first, its choice index is 0" "Choices Followup">><</textchoice>>
<<tchoice "I'm picking the second, its choice index is 1" "Choices Followup">>
<<tchoice "I'm picking the third, its choice index is 2" "Choices Followup">><<set _choice = sp.choiceMadeIn("Choices")>>
<<send>>I'm picking the <<if _choice === 0>>first<<elseif _choice === 1>>second<<else>>third<</if>>, its choice index is _choice.<</send>>
<<receive>>Very cool! Thanks for letting me know<</receive>>
<<tfinish>><<set _m = "Mom">><<set _d = "Dad">>
<<receive _m>>This is some flavour text<</receive>>
<<send>>Some fun little banter!<</send>>
<<receive _d>>It's not necessary, though<</receive>><hr>
<<receive "Dad">>Received messages are different in group chats.<</receive>>
<<receive "Mom">>A valid contactKey MUST be passed to each receive widget<</receive>>
<<send>>But sent messages work the same as always<</send>>
<<receive "Dad" "dadman">>You can still specify per-message names, though!<</receive>>
<<receive "Dad">>Otherwise I go back to my defined name, "Dad"<</receive>>
<<tfinish>><hr>
<<send>>So we can now use the temp variables here?<</send>>
<<receive _d>>Yep!<</receive>>
<<receive _d "Dadman">>And of course, I can still be "Dadman" if I want to sometimes<</receive>>
<<receive _m>>Not often, I hope<</receive>>
<<tfinish>><p>This is where reminders are located! It's going to need some extra styling, though, unless you like your text center-aligned.</p>
<p>The phone gives chats per-contact classes so you can change the style of this chat without messing with any others.</p>
<p>Some HTML will likely be necessary, since the phone does not allow <nowiki><br></nowiki> elements to be used outside of text messages by default. That prevents SugarCube from accidentally throwing off the phone's styling.</p><p>Here's the gallery! We made the text huge. We also have an image in here.</p>
[img[images/icon.png]]
<p>Chats will always scroll themselves to the bottom. Scroll up to see previous items in this chat.</p><<receive>>Here's a sample chat to fill up the phone<</receive>>
<<send>>Cool. Thx dad<</send>>
<<receive>>Talk to you later<</receive>>
<<send>>ttyl<</send>><hr>
<<send>>What's that at the start of this sample?<</send>>
<<receive>>The line between this chat and the previous one is a simple flourish.<</receive>>
<<receive>>It's made with an <nowiki><hr></nowiki> element. It can set different conversations apart from one another<</receive>>
<<send>>That's very neat<</send>>
<<receive>>Just try to keep them at the top of chats<</receive>>
<<receive>>If it's placed anywhere else, the line will jump around in live chats<</receive>><hr>
<<receive>>Hope you enjoy the demo, anyway<</receive>>
<<send>>I will<</send>><<send>>We're putting a bit of fun pre-game banter here<</send>>
<<send>>Not every chat needs to be a live texting experience!<</send>>
<<receive>>Having a couple messages for contacts the player's character knows before the game can be nice<</receive>>
<<receive>>It's certainly not required, though<</receive>><hr>
<<send>>Oh, we forgot something, right?<</send>>
<<receive>>Yep. Make sure to check out the phone options in the side bar<</receive>>
<<receive>>Toggling them should make the chats look different the next time they're loaded<</receive>>
<<send>>That's pretty dope<</send>>
<<receive>>No one says dope anymore. bye<</receive>><<receive>>We've just got some more friendly sample chats here<</receive>>
<<receive>>You know. usual stuff<</receive>>
<<send>>Neat<</send>><hr>
<<receive>>Oh, player, before I forget, you can do this:<</receive>>
<<receive>>😎<</receive>>
<<send>>Did you use the HTML code for an emoji?<</send>>
<<receive>>yep! That one has the code <nowiki>😎</nowiki><</receive>>
<<receive>>HTML codes for other emojis can be found online!<</receive>><h1>Advanced Topics Introduction</h1>
For those interested in making more significant changes to SugarPhone, the topics in this section should provide further information on the inner workings of the phone. They are not exhaustive, however, and serve mainly to inform you of your options.
This includes the <nowiki>$phone</nowiki> object, which holds all of the phone's persistent data, the phone's structure, and suggestions for alternative uses of the phone, such as image galleries and reminders.
<div class="note"><b>NOTE:</b> There are phone methods and widgets that are not documented in the official sections or here. This includes all of the phone's static methods, which handle loading and advancing chats and more. Omitted methods and widgets are still documented in the pretty versions of all code.</div>
<div class="see"><b>SEE:</b> [[Phone Structure]] documentation.</div>
<<include "Advanced Topics Index">><h3>Advanced Topics</h3>
<ul class="compact-list">
<<if passage() != "Advanced Topics">><li>[[Introduction|Advanced Topics]]</li>
<</if>><<if passage() != "Alternative SugarPhone Uses">><li>[[Alternative SugarPhone Uses]]</li>
<</if>><<if passage() != "Persistent Phone Data">><li>[[Persistent Phone Data]]</li>
<</if>><<if passage() != "Using Variables">><li>[[Using Variables in Chats|Using Variables]]</li><</if>>
</ul><h1>Alternative SugarPhone Uses</h1>
While SugarPhone is designed for live text conversations, other uses of contacts are permitted and encouraged.
Two potential uses include storing task lists/to do lists for players, as well as image galleries or other forms of information reference--you could even put your inventory in the phone!
<div class="note"><b>NOTE:</b> This section briefly goes over the ways you can style your alternate chats. You can see [[Phone Structure]] for more information on its elements and how to target their CSS on a per-contact basis.</div>
<hr>
Most of the bells and whistles of the phone are a result of the texting widgets (<nowiki><<send>></nowiki>/<nowiki><<receive>></nowiki>) and choice widgets (<nowiki><<textchoice>></nowiki>/<nowiki><<tchoice>></nowiki>) in live chats, and so inactive chats without those widgets can behave more like a passage.
Let's try this out by adding a reminders contact to the phone.
<pre><nowiki><<addcontact "reminders" "Reminders">></nowiki></pre>
Just like a regular contact! However, we want to make it clear to players that this is //not// a regular contact. We'll use the following code so that the contact link appears at the very <b>bottom</b> of the contact list.
<pre><nowiki>#phone-contacts .reminders-row {
margin-top: auto;
order: 1;
}</nowiki></pre>
SugarPhone automatically assigns contact links a class that follows the following format: <nowiki>contactKey-row</nowiki>. This is how the <nowiki>reminders-row</nowiki> class is generated.
The <nowiki>order: 1</nowiki> property ensures that the contact link will <b>last</b> out of all contact links.
The <nowiki>margin-top: auto</nowiki> property makes it so that in addition to being last, the Reminders link will be at the bottom of the contact list separated from the links above when whitespace is available (does not apply to mobile format).
Use the link below to add the one and only reminders chat.
<<link "Add Reminders">><<receivechat "reminders" "Reminders">><<textalert "reminders">><</link>>
<<link "Ignore Junk test">><<ignorechat "rem">><</link>>
<<link "Ignore Inactive test">><<ignorechat "reminders">><</link>>
You'll notice that an alert was created but no live texting can occur in the reminders chat. The code of the link is below:
<pre><nowiki><<link "Add Reminders">>
<<receivechat "reminders" "Reminders">>
<<textalert "reminders">>
<</link>></nowiki></pre>
The <nowiki><<textalert>></nowiki> widget notes that the <nowiki>reminders</nowiki> contact should be checked! It creates an alert that persists until ignored or the chat is opened for the first time.
<div class="note"><b>NOTE:</b> If you have multiple contact links you wish to set apart, only the ''first'' separate row needs the <nowiki>margin-top: auto</nowiki> rule. The first is determined by the <nowiki>order</nowiki> number--the higher the number, the lower on the list it will go relative to others.</div>
If you want to add a gallery in addition to reminders, for example, we'll use the following code:
<pre><nowiki><<addcontact "Gallery">> → Create the "Gallery" contact
<<receivechat "Gallery" "Gallery">> → Add "Gallery Chat Gallery" to the chat history </nowiki></pre>
Click the link below to display the "Gallery" contact.
<<link "Add Gallery">><<updatecontact "Gallery" "display" true>><<textalert "Gallery">><</link>>
It has a bit more CSS that specifies it an <nowiki>order</nowiki> value greater than <nowiki>.reminders-row</nowiki>:
<pre><nowiki>#phone-contacts .Gallery-row {
order: 2;
}</nowiki></pre>
That's all there is to it. Any further styling and fanciness can be done inside the chat because in the same way each contact row gets a custom class, so does the chat (<nowiki>#chat</nowiki>).
Instead of <nowiki>contactKey-row</nowiki>, it gets the class <nowiki>contactKey-chat</nowiki>.
A simple example below increases the font-size and aligns all text to the left.
<pre><nowiki>#chat.Gallery-chat {
font-size: 2em;
text-align: left;
}</nowiki></pre>
You may also target <nowiki>#chat-int</nowiki> (the interior element of <nowiki>#chat</nowiki>!) to alter properties such as padding.
<pre><nowiki>.gallery-Chat #chat-int {
padding: 1em;
}</nowiki></pre><h1>Persistent Phone Data</h1>
This <nowiki>$phone</nowiki> object contains all persistent phone data. This is the data that must be a part of the story history. This includes phone settings, live chats, and contacts and their history.
Other information, such as the UI state or the current active chat contact, is stored in the <nowiki>sp</nowiki> object and does not need to persist.
The [[config settings|SugarPhone Settings]] should be the only properties that are changed directly. All other properties are best handled by the phone.
When it comes to checking and changing contacts and their histories, the [[widgets|Phone Widget Documentation]] and [[API|SugarPhone API]] are best.
The widgets or methods relevant to each of the phone's properties are noted, though some have been omitted.
<div class="note"><b>NOTE:</b> You can track <nowiki>$phone</nowiki> in Test/Debug Mode to ensure information is being tracked as desired.</div>
<<include "Phone Data Index">>
<h3 id="phone-obj-complete"><nowiki>
$phone
</nowiki></h3>
For reference, the phone's initial state (from the install code) is below.
<pre><nowiki><<set $phone = {
config: {
alertIcon: "",
allowChatIconRepeat: false,
allowChatNameRepeat: false,
chatLoadDelay: 500,
chatNameInfix: " Chat ",
chatScrollSpeed: 600,
disableChoiceHistory: false,
disableIgnoredChatHistory: false,
displayChatIcons: false,
displayChatNames: true,
docked: true,
maxLoadedChats: 25,
playerIcon: "",
playerName: "",
popupAlerts: false,
pressPToToggle: false
},
contacts: {},
hide: false,
liveChats: {},
locked: false
}>></nowiki></pre>
<hr>
<h3 id="phone-obj-contacts"><nowiki>
$phone.contacts
</nowiki></h3>
The contacts property holds all contacts defined by <nowiki><<addcontact>></nowiki> or <nowiki><<addcontactgroup>></nowiki>, accessible by their <nowiki>contactKey</nowiki>.
Contact objects can be returned by <nowiki>sp.getContact()</nowiki>.
<h4>Examples:</h4>
<b>Contact initialization code directly from <nowiki><<addcontact>></nowiki></b>
<pre><nowiki>// _name and _icon are relevant strings, with _icon potentially empty
<<set $phone.contacts[_contactKey] = {
alert: false,
chats: [],
choices: {},
display: true,
icon: _icon,
ignoredChats: [],
name: _name
}>></nowiki></pre>
<b>Get a contact with <nowiki>sp.getContact()</nowiki></b>
<pre><nowiki>// Returns null if "contactKey" is undefined
// Only use with temporary variables
<<set _contact = sp.getContact("contactKey")>></nowiki></pre>
<h4>Associated API Methods & Widgets:</h4>
<ul>
<li><b>Methods:</b> <nowiki>chatIgnored()</nowiki>, <nowiki>chatLiveWith()</nowiki>, <nowiki>chatLiveWithAny()</nowiki>, <nowiki>contactExists()</nowiki>, <nowiki>getContact()</nowiki>, <nowiki>getContactKeys()</nowiki>, <nowiki>getLiveContacts()</nowiki>, <nowiki>getName()</nowiki>, <nowiki>hadChat()</nowiki>, <nowiki>ignoreChat()</nowiki>, <nowiki>purgeContactHistory()</nowiki>, <nowiki>removeContact()</nowiki></li>
<li><b>Widgets:</b> <nowiki><<addcontact>></nowiki>, <nowiki><<addcontactgroup>></nowiki>, <nowiki><<ignoreallchats>></nowiki>, <nowiki><<ignorechat>></nowiki>, <nowiki><<receivechat>></nowiki>, <nowiki><<removecontact>></nowiki>, <nowiki><<sendchat>></nowiki>, <nowiki><<textalert>></nowiki>, <nowiki><<updatecontact>></nowiki></li>
</ul>
<h4>Property Breakdown:</h4>
<ul>
<li><nowiki>alert</nowiki>: When true, an alert will appear in the phone's header, beside the contact's name in the phone's contact list, and in all <nowiki><<powerbutton>></nowiki> buttons. It is set to <nowiki>false</nowiki> once a chat is loaded or ignored.
<ul>
<li><b>Methods:</b> <nowiki>getAlertCount()</nowiki>, <nowiki>ignoreChat()</nowiki>, <nowiki>updateAlerts()</nowiki></li>
<li><b>Widgets:</b> <nowiki><<ignoreallchats>></nowiki>, <nowiki><<ignorechat>></nowiki>, <nowiki><<textalert>></nowiki>, <nowiki><<updatealerts>></nowiki></li>
</ul>
</li>
<li><nowiki>chats</nowiki>: A list of <nowiki>chatKeys</nowiki> in the order they were added.
<ul>
<li><b>Methods:</b> <nowiki>_addChat()</nowiki>, <nowiki>chatIgnored()</nowiki>, <nowiki>chatPassageExists()</nowiki>, <nowiki>choiceMadeIn()</nowiki>, <nowiki>getChatName()</nowiki>, <nowiki>hadChat()</nowiki>, <nowiki>ignoreChat()</nowiki>, <nowiki>madeChoice()</nowiki>, <nowiki>purgeContactHistory()</nowiki>, <nowiki>removeChat()</nowiki></li>
<li><b>Widgets:</b> <nowiki><<ignoreallchats>></nowiki>, <nowiki><<ignorechat>></nowiki>, <nowiki><<receivechat>></nowiki>, <nowiki><<removechat>></nowiki>, <nowiki><<sendchat>></nowiki>, <nowiki><<tchoice>></nowiki>, <nowiki><<textchoice>></nowiki></li>
</ul>
</li>
<li><nowiki>choices</nowiki>: Key value pairs where the key is a <nowiki>chatKey</nowiki> and the value is the <nowiki>choiceIndex</nowiki> selected in that chat.
<ul>
<li><b>Methods:</b> <nowiki>choiceMadeIn()</nowiki>, <nowiki>madeChoice()</nowiki></li>
<li><b>Widgets:</b> <nowiki><<tchoice>></nowiki>, <nowiki><<textchoice>></nowiki></li>
</ul>
</li>
<li><nowiki>display</nowiki>: Should a contact be visible when at least one chat exists in their chat history.
<ul>
<li><b>Widgets:</b> <nowiki><<updatecontact>></nowiki></li>
</ul>
</li>
<li><nowiki>icon</nowiki>: The filepath to a contact's icon.
<ul>
<li><b>Widgets:</b> <nowiki><<updatecontact>></nowiki></li>
</ul>
</li>
<li><nowiki>ignoredChats</nowiki>: A list of <nowiki>chatKeys</nowiki> that have been ignored.
<ul>
<li><b>Methods:</b> <nowiki>chatIgnored()</nowiki>, <nowiki>ignoreChat()</nowiki></li>
<li><b>Widgets:</b> <nowiki><<ignoreallchats>></nowiki>, <nowiki><<ignorechat>></nowiki></li>
</ul>
</li>
<li><nowiki>name</nowiki>: The name to display in the contact list and with <nowiki><<receive>></nowiki> messages by this contact.
<ul>
<li><b>Methods:</b> <nowiki>getName()</nowiki></li>
<li><b>Widgets:</b> <nowiki><<updatecontact>></nowiki></li>
</ul>
</li>
</ul>
<hr>
<h3 id="phone-obj-hide"><nowiki>
$phone.hide
</nowiki></h3>
Whether the phone should be hidden when locked.
This property is set by the <nowiki><<lockphone>></nowiki> widget's optional argument, <nowiki>hide</nowiki>. It becomes <nowiki>false</nowiki> whenever <nowiki><<unlockphone>></nowiki> is used.
<div class="note"><b>NOTE:</b> Undocked phones are always hidden when closed or locked.</div>
<h4>Associated API Methods & Widgets:</h4>
<ul>
<li><b>Methods:</b> <nowiki>lock()</nowiki>, <nowiki>unlock()</nowiki></li>
<li><b>Widgets:</b> <nowiki><<lockphone>></nowiki>, <nowiki><<unlockphone>></nowiki></li>
</ul>
<hr>
<h3 id="phone-obj-live-chats"><nowiki>
$phone.liveChats
</nowiki></h3>
An object of key value pairs tracking progress into all live chats.
The key is some valid <nowiki>contactKey</nowiki> with a live chat. The value is the depth (number of messages) reached into the contact's most recent chat.
<h4>Associated API Methods & Widgets:</h4>
<ul>
<li><b>Methods:</b> <nowiki>chatLiveWith()</nowiki>, <nowiki>chatLiveWithAny()</nowiki>, <nowiki>_endChatWith()</nowiki>, <nowiki>getLiveContacts()</nowiki>, <nowiki>ignoreChat()</nowiki></li>
<li><b>Widgets:</b> <nowiki><<ignoreallchats>></nowiki>, <nowiki><<ignorechat>></nowiki>, <nowiki><<receivechat>></nowiki>, <nowiki><<sendchat>></nowiki></li>
</ul>
<hr>
<h3 id="phone-obj-locked"><nowiki>
$phone.locked
</nowiki></h3>
Whether the phone should be accessible or not.
When <nowiki>true</nowiki>, the phone cannot be opened by any means.
<h4>Associated API Methods & Widgets:</h4>
<ul>
<li><b>Methods:</b> <nowiki>lock()</nowiki>, <nowiki>unlock()</nowiki></li>
<li><b>Widgets:</b> <nowiki><<lockphone>></nowiki>, <nowiki><<unlockphone>></nowiki></li>
</ul><h3>Persistent Phone Data</h3>
<ul class="compact-list">
<li><a href="#phone-obj-complete"><nowiki>$phone</nowiki></a></li>
<li><a href="#phone-obj-contacts"><nowiki>$phone.contacts</nowiki></a></li>
<li><a href="#phone-obj-hide"><nowiki>$phone.hide</nowiki></a></li>
<li><a href="#phone-obj-live-chats"><nowiki>$phone.liveChats</nowiki></a></li>
<li><a href="#phone-obj-locked"><nowiki>$phone.locked</nowiki></a></li>
</ul>
<hr><h1>Using Variables in Chats</h1>
<<include "Chat Variable Warning">>
There are are two general approaches you can take to avoid fluctuating phone histories.
You may also implement your own solutions or frameworks, but be wary of bloating your story's data.
<a href="#vars-control-flow">1. Control Flow with <nowiki><<textchoice>></nowiki></a>
<a href="#vars-max-chats">2. Lower <nowiki>$phone.config.maxChats</nowiki></a>
<hr>
<h2 id="vars-control-flow">1. Control Flow</h2>
In the above example for <nowiki>$ryan.affection</nowiki>, the easiest way to avoid chats displaying the incorrect state is to have a different chat for each state.
<b>Bad: A single chat with multiple states</b>
<pre><nowiki><<link "Check in with Ryanald">>
<<sendchat "ryan" "Check In" true>>
<</link>></nowiki></pre>
<b>Good: A chat for each significant state</b>
<pre><nowiki><<link "Check in with Ryanald">>
<<if $ryan.affection > 5>>
<<sendchat "ryan" "Check In Like" true>>
<<else>>
<<sendchat "ryan" "Check In Dislike" true>>
<</if>>
<</link>></nowiki></pre>
While making separate chats might be a bit more writing, it's far less likely to cause problems in your story.
If only a few messages need to change in your chat, you may use <nowiki><<include>></nowiki> for messages that are identical between chats.
<b>Including messages consistent between "Dislike" and "Like" branches</b>
<pre><nowiki> :: ryan Chat Check In Like
<<send>>Hey Ryanald, how are you doing???<</send>>
<<receive>>I'm doing well! Thank you so much for asking<</receive>>
<<include "ryan checkin">>
:: ryan Chat Check In Dislike
<<send>>Hello Ryanald, I was just hoping to check in<</send>>
<<receive>>im fine<</receive>>
<<include "ryan checkin">>
:: ryan checkin
// This chat is not a part of the chat history, which means we can name it flexibly
// That also means it can't be referenced by the API
<<receive>>I do have a question for you though<</receive>>
<<receive>>Can you help me with the project?<</receive>>
<<tchoice "Of course" "Project Yes">>
<<tchoice "No, sorry" "Project No">></nowiki></pre>
As alluded to above, there is a caution: the choices in "ryan checkin" are going to be associated with the chat that <nowiki><<include>></nowiki> them. That means they could be associated with the <nowiki>chatKey</nowiki> "Check In Dislike" OR "Check In Like". This is a case where <nowiki>sp.hadChat()</nowiki> (to check "Project Yes" or "Project No") will be far easier than using the <nowiki>sp.choiceMadeIn()</nowiki> or <nowiki>sp.madeChoice()</nowiki> methods.
<nowiki><<textchoice>></nowiki> links can be used for control flow as well since they can only be interacted with once. This can be used to infer the value of variables retroactively, based on decisions made.
<div class="see"><b>SEE:</b> [[Checking Choices]]</div>
<b>Example in a chat</b>
<pre><nowiki><<if $josh.affection > 20>>
<<textchoice "Ask Joshamy out on a date" "Ask On Date">>
<<else>>
<<textchoice "Say goodnight" "Goodnight">>
<</if>></nowiki></pre>
<hr>
<h2 id="vars-max-chats">2. Lower <nowiki>$phone.config.maxChats</nowiki></h2>
Having fewer visible chats means more flexibility in the variables you use in the most recent chats.
You may even set <nowiki>maxChats</nowiki> to 1 so that only the most recent chat is visible. This only applies to freshly loaded chats, so no chats are removed when having a conversation with multiple branches.
<div class="see"><b>SEE:</b> <nowiki>$phone.config.maxChats</nowiki> in [[SugarPhone Settings]].</div><h2 id="chat-variable-warning">Warning:</h2>
SugarPhone does ''not'' remember the state variables used in its chats.
Because of this, if you reference variables subject to change, expect your past messages to change as well. This can be especially jarring when <nowiki><<if>></nowiki> statements are used frequently instead of conversation branches.<<if passage() !== "Using Variables">>
<div class="see"><b>SEE:</b> [[Using Variables]] for more information.</div><</if>>
<b>Bad: The if statement is reevaluated each time the chat loads</b>
<pre><nowiki><<send>>Hey, Ryanald!<</send>>
<<if $ryan.affection > 5>>
<<receive>>$player.name! I was looking forward to hearing from you<</receive>>
<<else>>
<<receive>>What do you want?<</receive>>
<</if>></nowiki></pre>
<b>Better: Checking a chat that MUST have been received before now</b>
<pre><nowiki>// Be cautious if a chat may still happen in the future
<<send>>Hey, Ryanald!<</send>>
<<if sp.chatIgnored("Hang Out", "ryan")>>
<<receive>>So now you're finally getting back to me?<</receive>>
<<else>>
<<receive>>Hey, what's up?<</receive>>
<</if>></nowiki></pre>
<hr><h1>SugarPhone API</h1>
When you want information about the state and history of the phone and its contacts, the SugarPhone API is your safest point of contact. It should only be accessed through the <nowiki>sp</nowiki> (short for SugarPhone) object.
When making changes to the phone, contacts, and chats, the [[phone's widgets|Phone Widget Documentation]] are your best tool.
There is overlap between the widgets and methods, though, and some can be used interchangeably based on preference or need (such as <nowiki><<openphone>></nowiki> and <nowiki>sp.open()</nowiki>, which are identical in function). Methods with corresponding widgets are noted.
<<include "Chat Variable Warning">>
<<include "Object Reference Warning">>
<<include "SugarPhone API Index">>
<h2 id="public-methods">Public Methods</h2>
<<nobr>><h3 id="function-chat-ignored">
<nowiki>chatIgnored([chatKey=currentChatKey], [contactKey=activeContactKey])</nowiki> → <em>boolean</em>
</h3><</nobr>>
Returns whether a chat was ignored, or <nowiki>null</nowiki> if it is not part of the chat history.
<div class="see"><b>SEE:</b> <nowiki>$phone.config.disableIgnoredChatHistory</nowiki> in [[SugarPhone Settings|SugarPhone Settings]]</div>
<h4>Parameters:</h4>
<ul>
<li><nowiki>chatKey</nowiki>: (optional, <i>string</i>) Suffix for some chat passage. If omitted and a chat is open, it will be inferred while the chat is loading.</li>
<li><nowiki>contactKey</nowiki>: (optional, <i>string</i>) Unique key used to define the contact. If omitted and a chat is open, the active contact's key will be used.</li>
</ul>
<h4>Examples:</h4>
<b>Check if the current chat was ignored</b>
<pre><nowiki><<receive>>Hey, I need some help<</receive>>
<<if sp.chatIgnored()>> // null result impossible
<<receive>>Never mind, you must be busy.<</receive>>
<<else>>
<<receive>>I need someone to help me study<</receive>>
<</if>></nowiki></pre>
<b>Check if some previous chat with the active contact was ignored</b>
<pre><nowiki><<receive>>So, what do you remember about Important Information?<</receive>>
<<if sp.chatIgnored("Important Information")>>
<<tchoice "I don't know anything" "Important Information Redux">>
<<else>>
<<tchoice "I know everything there is to possibly know" "Continue Chat">>
<</if>></nowiki></pre>
<b>Check if a specified chat with a specified contact was ignored</b>
<pre><nowiki><<if sp.chatIgnored("Proposal", "tay") === false>>
The chat "tay Chat Proposal" was received/sent and finished
<<elseif sp.chatIgnored("Proposal", "tay") === null>>
The chat "tay Chat Proposal" was never received/sent
<<else>>
The chat "tay Chat Proposal" was ignored
<</if>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-chat-live-with">
<nowiki>chatLiveWith([contactKey=activeContactKey])</nowiki> → <em>boolean</em>
</h3><</nobr>>
Returns whether a chat is live with a contact.
<h4>Parameters:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: (optional, <i>string</i>) Unique key used to define the contact. If omitted and a chat is open, the active contact's key will be used.</li>
</ul>
<h4>Examples:</h4>
<b>Add new chats if one is not currently live</b>
<pre><nowiki><<if !sp.chatLiveWith("Dad")>>
<<receivechat "Dad" "Some Conversation" true>>
<</if>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-chat-live-with-any">
<nowiki>chatLiveWithAny()</nowiki> → <em>boolean</em>
</h3><</nobr>>
Returns whether a chat is live with at least one contact.
<h4>Examples:</h4>
<b>Prevent player actions if chats are live</b>
<pre><nowiki><<link "Sleep">>
<<if !sp.chatLiveWithAny()>>
<<goto "Wake Up">>
<</if>>
<<link>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-chat-passage-exists">
<nowiki>chatPassageExists(contactKey, chatKey)</nowiki> → <em>boolean</em>
</h3><</nobr>>
Returns whether the inputs create an extant passage name.
Chat passage names are created as follows: <nowiki>contactKey + $phone.config.chatNameInfix + chatKey</nowiki>.
<div class="see"><b>SEE:</b> <a href="#function-get-chat-name"><nowiki>getChatName()</nowiki></a>, <nowiki>$phone.config.chatNameInfix</nowiki> in [[SugarPhone Settings]].</div>
<h4>Parameters:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: (<i>string</i>) Unique key used to define the contact.</li>
<li><nowiki>chatKey</nowiki>: (<i>string</i>) Suffix for some chat passage.</li>
</ul>
<h4>Examples:</h4>
<pre><nowiki>→ Assuming $phone.config.chatNameInfix is " Chat " (default)
<<if sp.chatPassageExists("Greg", "Introduction")>>The passage "Greg Chat Introduction" exists<</if>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-choice-made-in">
<nowiki>choiceMadeIn(chatKey, [contactKey=activeContactKey])</nowiki> → <em>integer</em>
</h3><</nobr>>
Returns the 0-indexed order number of a <nowiki><<textchoice>></nowiki>/<nowiki><<tchoice>></nowiki> link relative to others in the same chat.
Returns <nowiki>null</nowiki> if the chat is not part of the chat history.
<<include "Choice Index Warning">>
<div class="see"><b>SEE:</b> <nowiki>$phone.config.disableChoiceHistory</nowiki> in [[SugarPhone Settings]]</div>
<h4>Parameters:</h4>
<ul>
<li><nowiki>chatKey</nowiki>: (<i>string</i>) Suffix for some chat passage.</li>
<li><nowiki>contactKey</nowiki>: (optional, <i>string</i>) Unique key used to define the contact. If omitted and a chat is open, the active contact's key will be used.</li>
</ul>
<h4>Examples:</h4>
<b>In a chat, print the choice index from some previous chat with the active contact</b>
<pre><nowiki><<receive>>Remind me which option you chose?<</receive>>
<<send>>I chose option #<<=sp.choiceMadeIn("Some Chat")>><</send>></nowiki></pre>
<b>Check a choice made with a specified contact</b>
<pre><nowiki><<receive>>What did you tell Mom?<</receive>>
<<send>> // Line breaks are ignored unless done via <br> element
<<if sp.choiceMadeIn("Some Chat", "Mom") === 0>>
I didn't tell her anything
<<else>>
I told her everything
<</if>>
<</send>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-close-phone">
<nowiki>closePhone()</nowiki>
</h3><</nobr>>
Closes the phone if it is open.
<div class="note"><b>NOTE:</b> <nowiki>sp.closePhone()</nowiki> is identical to <nowiki><<closephone>></nowiki>.</div>
<h4>Examples:</h4>
<pre><nowiki><<run sp.closePhone()>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-contact-exists">
<nowiki>contactExists(contactKey)</nowiki> → <em>boolean</em>
</h3><</nobr>>
Returns whether a contact has been defined with this key.
<h4>Parameters:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: (<i>string</i>) Unique key used to define the contact.</li>
</ul>
<h4>Examples:</h4>
<b>Check if contact exists before adding random chats</b>
<pre><nowiki><<set _textChance = random(0, 100)>>
<<if _textChance > 50>>
<<if sp.contactExists("Friend1")>>
... potentially send some chat
<</if>>
<</if>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-get-alert-count">
<nowiki>getAlertCount()</nowiki> → <em>integer</em>
</h3><</nobr>>
Returns the total number of contact alerts.
This may be useful if you would make to display your own alerts or text.
<div class="note"><b>NOTE:</b> A chat may be live without having an alert. Conversely, a chat may be inactive and have an alert via <nowiki><<textalert>></nowiki>.</div>
<div class="see"><b>SEE:</b> <a href="#function-chat-live-with"><nowiki>chatLiveWith()</nowiki></a>, <a href="#function-chat-live-with-any"><nowiki>chatLiveWithAny()</nowiki></a>, <a href="#function-get-live-contacts"><nowiki>getLiveContacts()</nowiki></a>.</div>
<h4>Examples:</h4>
<b>Simple use</b>
<pre><nowiki>You have <<=sp.getAlertCount()>> messages pending.</nowiki></pre>
<b>Use a loop to do something for each alert</b>
<pre><nowiki><<for _i = 0; _i < sp.getAlertCount(); _i++>>
... do something
<</for>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-get-chat-name">
<nowiki>getChatName(contactKey, chatKey)</nowiki> → <em>string</em>
</h3><</nobr>>
Returns an un-validated passage name following chat passage name format.
Chat passage name format is the following: <nowiki>contactKey + $phone.config.chatNameInfix + chatKey</nowiki>.
This method is likely most helpful for testing or modding rather than game play.
<div class="see"><b>SEE:</b> <a href="#function-chat-passage-exists"><nowiki>chatPassageExists()</nowiki></a>, <nowiki>$phone.config.chatNameInfix</nowiki> in [[SugarPhone Settings]].</div>
<h4>Parameters:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: (<i>string</i>) Unique key used to define the contact.</li>
<li><nowiki>chatKey</nowiki>: (<i>string</i>) Suffix for some chat passage.</li>
</ul>
<h4>Examples:</h4>
<pre><nowiki><<print sp.getChatName("Dad", "Some Chat")>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-get-contact">
<nowiki>getContact([contactKey=activeContactKey])</nowiki> → <em>object</em>
</h3><</nobr>>
Returns the reference for a contact, or <nowiki>null</nowiki> if none exists.
<div class="see"><b>SEE:</b> <a href="#function-get-contact-keys"><nowiki>getContactKeys()</nowiki></a>, <a href="#function-get-name"><nowiki>getName()</nowiki></a>, <a href="#object-reference-warning">Object reference warning</a>.</div>
<h4>Parameters:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: (optional, <i>string</i>) Unique key used to define the contact. If omitted and a chat is open, the active contact's key will be used.</li>
</ul>
<h4>Examples:</h4>
<b>Make a temporary reference to an active contact</b>
<pre><nowiki>// If no chat is open, _activeContact will be null
<<set _activeContact = sp.getContact()>></nowiki></pre>
<b>Make a temporary reference to the contact "Dad"</b>
<pre><nowiki><<set _dad = sp.getContact("Dad")>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-get-contact-keys">
<nowiki>getContactKeys()</nowiki> → <em>Array<nowiki><string></nowiki></em>
</h3><</nobr>>
Returns an array of all contact keys.
<div class="see"><b>SEE:</b> <a href="#function-get-contact"><nowiki>getContact()</nowiki></a>.</div>
<h4>Examples:</h4>
<b>Create a list of keys with their contact names</b>
<pre><nowiki><ul>
<<for _contactKey range sp.getContactKeys()>>
<li>_contactKey: <<=sp.getName(_contactKey)>></li>
<</for>>
</ul></nowiki></pre>
<hr>
<<nobr>><h3 id="function-get-live-contacts">
<nowiki>getLiveContacts(names=false)</nowiki> → <em>object</em>
</h3><</nobr>>
Returns a list of contacts with live chats.
<div class="see"><b>SEE:</b> <a href="#function-chat-live-with"><nowiki>chatLiveWith()</nowiki></a>, <a href="#function-chat-live-with-any"><nowiki>chatLiveWithAny()</nowiki></a>, <a href="#function-get-alert-count"><nowiki>getAlertCount()</nowiki></a>, <a href="#function-get-contact-keys"><nowiki>getContactKeys()</nowiki></a>, <a href="#function-get-name"><nowiki>getName()</nowiki></a>.</div>
<h4>Parameters:</h4>
<ul>
<li><nowiki>names:</nowiki> (optional) Should the list contain contact names instead of <nowiki>contactKeys</nowiki>.</li>
</ul>
<h4>Examples:</h4>
<b>Loop through keys and do something with the contacts</b>
<pre><nowiki><<set _liveKeys = sp.getLiveContacts()>>
<<for _i = 0; _i > _liveKeys.length; _i++>>
<<set _contact = sp.getContact(_liveKeys[_i])>>
... do something
<</for>></nowiki></pre>
<b>Create a list of live contact names</b>
<pre><nowiki>→ Assuming _liveNames is ["Dad", "Friend"]
<<set _liveNames = sp.getLiveContacts(true)>>
You have messages waiting from the following contacts:
<ul>
<<for _i = 0; _i > _liveNames.length; _i++>>
<li><<print _i+1>>. _liveNames[_i]</li>
<</for>>
</ul>
→ Above outputs the following
You have messages waiting from the following people:
* 1. Dad
* 2. Friend</nowiki></pre>
<hr>
<<nobr>><h3 id="function-get-name">
<nowiki>getName([contactKey=activeContactKey])</nowiki> → <em>string</em>
</h3><</nobr>>
Returns the name of a contact, or <nowiki>null</nowiki> if the contact does not exist.
<div class="see"><b>SEE:</b> <a href="#function-get-contact"><nowiki>getContact()</nowiki></a>.</div>
<h4>Parameters:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: (optional, <i>string</i>) Unique key used to define the contact. If omitted and a chat is open, the active contact's key will be used.</li>
</ul>
<h4>Examples:</h4>
<b>Reference the active contact's name</b>
<pre><nowiki><<send>>Hey, how's it going <<=sp.getName()>>?<</send>></nowiki></pre>
<b>Create a list of all contact names</b>
<pre><nowiki><ul>
<<for _contactKey range sp.getContactKeys()>>
<li><<=sp.getName(_contactKey)>></li>
<</for>>
</ul></nowiki></pre>
<hr>
<<nobr>><h3 id="function-had-chat">
<nowiki>hadChat(contactKey, ...chatKeys)</nowiki> → <em>integer</em>
</h3><</nobr>>
Returns the number of provided chats present in a contact's chat history. Ignored chats are included in this number.
<h4>Parameters:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: (<i>string</i>) Unique key used to define the contact.</li>
<li><nowiki>chatKey</nowiki>: (<i>string</i> | <i>string[]</i>) Suffix for some number of possible chat passages.</li>
</ul>
<h4>Examples:</h4>
<b>Check if a single chat exists in the chat history</b>
<pre><nowiki><<if sp.hadChat("boss", "Promotion")>>
... The "Promotion" chatKey is a part of boss's chat history.
<</if>></nowiki></pre>
<b>Check if at least two chats exist in the chat history</b>
<pre><nowiki><<if sp.hadChat("boss", "Promotion", "Accept Offer", "Counter Offer") > 1>>
... At least 2 of the provided chatKeys are part of boss's chat history.
<</if>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-ignore-chat">
<nowiki>ignoreChat(contactKey)</nowiki>
</h3><</nobr>>
Ends a specified contact's live chat and alert.
If ignored chat history is enabled (default), the ignored live chat is recorded. If the chat is inactive but an alert was set, the alert is ended and no record is made.
<div class="note"><b>NOTE:</b> <nowiki>sp.ignoreChat("dad")</nowiki> is identical to <nowiki><<ignorechat "dad">></nowiki>.</div>
<div class="see"><b>SEE:</b> [[SugarPhone Settings]] to disable ignore history.</div>
<h4>Parameters:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: (<i>string</i>) Unique key used to define the contact.</li>
</ul>
<h4>Examples:</h4>
<pre><nowiki><<run sp.ignoreChat("josh")>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-lock">
<nowiki>lock([hide=false])</nowiki>
</h3><</nobr>>
Closes the phone if it's open and locks it. The phone must be unlocked to be opened again.
<nowiki><<powerbutton>></nowiki> buttons and <nowiki><<powerlink>></nowiki> links are also visually updated.
<div class="note"><b>NOTE:</b> <nowiki>sp.lock()</nowiki> and <nowiki>sp.lock(true)</nowiki> are identical to <nowiki><<lockphone>></nowiki> and <nowiki><<lockphone true>></nowiki>, respectively.</div>
<h4>Parameters:</h4>
<ul>
<li><nowiki>hide</nowiki>: (optional, <i>boolean</i>) Should the phone be hidden when locked. Only applies to docked phones; un-docked phones are already hidden when closed.</li>
</ul>
<h4>Examples:</h4>
<b>Lock the phone</b>
<pre><nowiki><<run sp.lock()>></nowiki></pre>
<b>Lock the phone and hide it</b>
<pre><nowiki><<run sp.lock(true)>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-made-choice">
<nowiki>madeChoice(choiceIndex, chatKey, [contactKey=activeContactKey])</nowiki> → <em>boolean</em>
</h3><</nobr>>
Returns whether a specific choice was selected in a specific chat. Always returns <nowiki>false</nowiki> when choice history is disabled.
<<include "Choice Index Warning">>
<div class="see"><b>SEE:</b> [[SugarPhone Settings]] to disable choice history.</div>
<h4>Parameters:</h4>
<ul>
<li><nowiki>choiceIndex</nowiki>: (<i>integer</i>) The 0-indexed order number of a text choice link relative to others in the same chat.</li>
<li><nowiki>chatKey</nowiki>: (<i>string</i>) Suffix for some chat passage.</li>
<li><nowiki>contactKey</nowiki>: (optional, <i>string</i>) Unique key used to define the contact. If omitted and a chat is open, the active contact's key will be used.</li>
</ul>
<h4>Examples:</h4>
<b>Within a chat, check a previous choice with the active contact</b>
<pre><nowiki><<receive>>Did you make the first choice, way back when?<</receive>>
<<if sp.madeChoice(0, "Previous Chat")>>
<<tchoice "I did!" "Branch A">>
<<else>>
<<tchoice "I didnt :(" "Branch B">>
<</if>></nowiki></pre>
<b>Check a choice made with a specified contact</b>
<pre><nowiki>"Did you make the second choice when talking to Dad?"
<<if sp.madeChoice(1, "Important Convo", "Dad")>>
"I made the second choice," you say.
<<else>>
"I made a different choice," you say. "Or I never had that conversation."
<</if>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-open-phone">
<nowiki>openPhone()
</nowiki></h3><</nobr>>
Opens the phone UI if it's currently closed and the phone is unlocked.
<div class="note"><b>NOTE:</b> <nowiki>sp.openPhone()</nowiki> is identical to <nowiki><<openphone>></nowiki>.</div>
<h4>Examples:</h4>
<pre><nowiki><<run sp.openPhone()>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-purge-contact-history">
<nowiki>purgeContactHistory(contactKey)</nowiki>
</h3><</nobr>>
Deletes all recorded chat history with a contact, including the chats, choice history, and ignore history.
<div class="warning"><b>WARNING:</b> This cannot be undone by SugarPhone.</div>
<div class="see"><b>SEE:</b> <a href="#function-remove-chat"><nowiki>removeChat()</nowiki></a>, <a href="#function-remove-contact"><nowiki>removeContact()</nowiki></a>.</div>
<h4>Parameters:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: (<i>string</i>) Unique key used to define the contact.</li>
</ul>
<h4>Examples:</h4>
<b>Reset a contact without altering name or icon</b>
<pre><nowiki><<run sp.purgeContactHistory("Dad")>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-remove-chat"><nowiki>
removeChat(contactKey, chatKey)</nowiki>
</h3><</nobr>>
Removes all instances of a <nowiki>chatKey</nowiki> and its related information for some contact.
If a contact's chat is live and the <nowiki>chatKey</nowiki> removed is the most recent chat, the chat will be made inactive during removal. Otherwise the chat will remain in its present state.
<div class="warning"><b>WARNING:</b> The <nowiki>chatKey</nowiki> will no longer exist in the contact's chat history. That means the choices and ignore state related to it will be wiped.</div>
<div class="note"><b>NOTE:</b> <nowiki>sp.removeChat("dad", "example")</nowiki> is identical to <nowiki><<removechat "dad" "example">></nowiki>.</div>
<div class="see"><b>SEE:</b> <a href="#function-purge-contact-history"><nowiki>purgeContactHistory()</nowiki></a>.</div>
<h4>Parameters:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: (<i>string</i>) Unique key used to define the contact.</li>
<li><nowiki>chatKey</nowiki>: (<i>string</i>) Suffix for some chat passage.</li>
</ul>
<h4>Examples:</h4>
<pre><nowiki>// Reset a quiz that takes place through the phone so it can be run again
<<run sp.removeChat("quiz")>>
<<receivechat "quiz" "First Question" true>> // Quiz chain can be safely restarted</nowiki></pre>
<hr>
<<nobr>><h3 id="function-remove-contact">
<nowiki>removeContact(contactKey)</nowiki>
</h3><</nobr>>
Removes a contact and all related information.
<div class="warning"><b>WARNING:</b> The contact will no longer exist in any capacity. Do not delete a contact if you rely on chat history and choices outside of that contact's chat.</div>
<div class="note"><b>NOTE:</b> <nowiki>sp.removeContact("dad")</nowiki> is identical to <nowiki><<removecontact "dad">></nowiki>.</div>
<div class="see"><b>SEE:</b> <a href="#function-purge-contact-history"><nowiki>purgeContactHistory()</nowiki></a>, <a href="#function-remove-chat"><nowiki>removeChat()</nowiki></a>.</div>
<h4>Parameters:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: (<i>string</i>) Unique key used to define the contact.</li>
</ul>
<h4>Examples:</h4>
<pre><nowiki><<run sp.removeContact("Dad")>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-unlock">
<nowiki>unlock()</nowiki>
</h3><</nobr>>
Allows the phone to be opened and the UI will return to its regular closed state.
<nowiki><<powerbutton>></nowiki> buttons and <nowiki><<powerlink>></nowiki> links will also visually update and become usable again.
<div class="note"><b>NOTE:</b> <nowiki>sp.unlock()</nowiki> is identical to <nowiki><<unlockphone>></nowiki>.</div>
<div class="see"><b>SEE:</b> <a href="#function-lock"><nowiki>lock()</nowiki></a>.</div>
<h4>Examples:</h4>
<pre><nowiki><<run sp.unlock()>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-update-alerts">
<nowiki>updateAlerts()</nowiki>
</h3><</nobr>>
Update all alerts in the phone header and <nowiki><<powerbutton>></nowiki> buttons. If the phone is open, the contact list is also reloaded.
Use <nowiki>sp.updateHeader()</nowiki> to update the header's other sections.
<div class="note"><b>NOTE:</b> SugarPhone calls this method when the phone is opened or closed, when chats are added, loaded, branched, and ignored, and a number of other niche situations.</div>
<div class="note"><b>NOTE:</b> <nowiki>sp.updateAlerts()</nowiki> is identical to <nowiki><<updatealerts>></nowiki>.</div>
<div class="see"><b>SEE:</b> <a href="#function-update-header"><nowiki>updateHeader()</nowiki></a>.</div>
<h4>Examples:</h4>
<pre><nowiki><<run sp.updateAlerts()>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-update-header">
<nowiki>updateHeader()</nowiki>
</h3><</nobr>>
Update the header's custom content divs if their optional passages exist.
The optional passages are <nowiki>SugarPhone Head Centre</nowiki> and <nowiki>SugarPhone Head Right</nowiki>.
<div class="note"><b>NOTE:</b> The phone's header updates fully during passage transitions, so this widget should only be necessary if custom content needs more frequent updates.</div>
<div class="note"><b>NOTE:</b> <nowiki>sp.updateHeader()</nowiki> is identical to <nowiki><<updateheader>></nowiki>.</div>
<div class="see"><b>SEE:</b> [[Adding to the Phone Header|Adding To Phone Header]].</div>
<h4>Examples:</h4>
<pre><nowiki><<run sp.updateHeader()>></nowiki></pre>
<hr>
<<nobr>><h2 id="protected-methods">Protected Methods</h2><</nobr>>
<<include "Protected Method Warning">>
<<nobr>><h3 id="function-add-chat">
<nowiki>_addChat(contactKey, chatKey, [dupe=false])</nowiki>
</h3><</nobr>>
Adds a chat to a contact's history.
<div class="warning"><b>WARNING:</b> The <nowiki>chatKey</nowiki> is not validated when passed directly to this function.</div>
<h4>Parameters:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: (<i>string</i>) Unique key used to define the contact.</li>
<li><nowiki>chatKey</nowiki>: (<i>string</i>) Suffix for some chat passage.</li>
<li><nowiki>dupe</nowiki>: (optional, <i>boolean</i>) Whether duplicates are allowed. If omitted, will default to <nowiki>false</nowiki>.</li>
</ul>
<hr>
<<nobr>><h3 id="function-contact-key-is-valid">
<nowiki>_contactKeyIsValid(contactKey)</nowiki>
</h3><</nobr>>
Returns whether a <nowiki>contactKey</nowiki> fits key criteria. The criteria are the same as naming a variable.
<h4>Parameters:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: (<i>string</i>) Contact key to validate.</li>
</ul>
<hr>
<<nobr>><h3 id="function-end-chat-with">
<nowiki>_endChatWith(contactKey)</nowiki>
</h3><</nobr>>
End all ongoing chat flags and alerts for a specific contact.
<h4>Parameters:</h4>
<ul>
<li><nowiki>contactKey</nowiki> (<i>string</i>) Unique key used to define the contact.</li>
</ul>
<hr>
<<nobr>><h3 id="function-get-alert-icon">
<nowiki>_getAlertIcon()</nowiki> → <i><nowiki>HTMLElement</nowiki></i> <em>object</em>
</h3><</nobr>>
Returns a span element for the phone's alert icon.
The default icon ''is'' the <nowiki><span></nowiki> element. Custom icons are an <nowiki><img></nowiki> within a <nowiki><span></nowiki> that has the class <nowiki>custom-alert-icon</nowiki>.
<div class="note"><b>NOTE:</b> This does not make any reference to the alert state of any contacts. It simply returns the HTML to display an alert.</div>
<div class="see"><b>SEE:</b> <nowiki>$phone.config.alertIcon</nowiki> in [[SugarPhone Settings]].</div>
<hr>
<<nobr>><h3 id="function-update-phone-toggles">
<nowiki>_updatePhoneToggles()</nowiki>
</h3><</nobr>>
Updates the state of <nowiki><<powerbutton>></nowiki> buttons and <nowiki><<powerlink>></nowiki> links.
In general, this should be used if you notice the buttons/links aren't updating as quickly as they should.
<div class="see"><b>SEE:</b> This function is called from the following methods: <a href="#function-lock"><nowiki>lock()</nowiki></a>, <a href="#function-unlock"><nowiki>unlock()</nowiki></a>, <a href="#function-update-alerts"><nowiki>updateAlerts()</nowiki></a>.</div><<nobr>><h3 id="protected-method-warning">Warning:</h3><</nobr>>
Unlike the API's public methods, the protected methods often ''do'' make significant changes to the phone and contacts, and they expect to do so from a limited set of circumstances.
These methods are described for documentation and modding purposes only, and you should not use them during regular game development.
Some protected methods have been omitted entirely. They are still documented in the phone's JavaScript.
<hr><<nobr>><h3 id="object-reference-warning">Warning:</h3><</nobr>>
Object references from methods such as <nowiki>getContact()</nowiki> should ''only'' be saved to temporary variables (those beginning with an underscore <nowiki>_</nowiki>).
Object references saved to story variables (those beginning with a sigil <nowiki>$</nowiki>) are ''broken'' upon passage transition. That means any changes made in the phone to the contact after the transition will not be reflected in the story variable.
Using temporary variables ensures you will never have a broken reference since they only exist for a single passage. It's far better to redefine them than to mistakenly work from outdated information.
<hr><h3><a href="#public-methods">Public Methods</a></h3>
<ul class="compact-list">
<li><a href="#function-chat-ignored"><nowiki>chatIgnored()</nowiki></a></li>
<li><a href="#function-chat-live-with"><nowiki>chatLiveWith()</nowiki></a></li>
<li><a href="#function-chat-live-with-any"><nowiki>chatLiveWithAny()</nowiki></a></li>
<li><a href="#function-chat-passage-exists"><nowiki>chatPassageExists()</nowiki></a></li>
<li><a href="#function-choice-made-in"><nowiki>choiceMadeIn()</nowiki></a></li>
<li><a href="#function-close-phone"><nowiki>closePhone()</nowiki></a></li>
<li><a href="#function-contact-exists"><nowiki>contactExists()</nowiki></a></li>
<li><a href="#function-get-alert-count"><nowiki>getAlertCount()</nowiki></a></li>
<li><a href="#function-get-chat-name"><nowiki>getChatName()</nowiki></a></li>
<li><a href="#function-get-contact"><nowiki>getContact()</nowiki></a></li>
<li><a href="#function-get-contact-keys"><nowiki>getContactKeys()</nowiki></a></li>
<li><a href="#function-get-live-contacts"><nowiki>getLiveContacts()</nowiki></a></li>
<li><a href="#function-get-name"><nowiki>getName()</nowiki></a></li>
<li><a href="#function-had-chat"><nowiki>hadChat()</nowiki></a></li>
<li><a href="#function-ignore-chat"><nowiki>ignoreChat()</nowiki></a></li>
<li><a href="#function-lock"><nowiki>lock()</nowiki></a></li>
<li><a href="#function-made-choice"><nowiki>madeChoice()</nowiki></a></li>
<li><a href="#function-open-phone"><nowiki>openPhone()</nowiki></a></li>
<li><a href="#function-purge-contact-history"><nowiki>purgeContactHistory()</nowiki></a></li>
<li><a href="#function-remove-chat"><nowiki>removeChat()</nowiki></a></li>
<li><a href="#function-remove-contact"><nowiki>removeContact()</nowiki></a></li>
<li><a href="#function-unlock"><nowiki>unlock()</nowiki></a></li>
<li><a href="#function-update-alerts"><nowiki>updateAlerts()</nowiki></a></li>
<li><a href="#function-update-header"><nowiki>updateHeader()</nowiki></a></li>
</ul>
<h3><a href="#protected-methods">Protected Methods</a></h3>
<ul class="compact-list">
<li><a href="#function-add-chat"><nowiki>_addChat()</nowiki></a></li>
<li><a href="#function-contact-key-is-valid"><nowiki>_contactKeyIsValid()</nowiki></a></li>
<li><a href="#function-end-chat-with"><nowiki>_endChatWith()</nowiki></a></li>
<li><a href="#function-get-alert-icon"><nowiki>_getAlertIcon()</nowiki></a></li>
<li><a href="#function-update-phone-toggles"><nowiki>_updatePhoneToggles</nowiki></a></li>
</ul>
<hr><h1>Phone Structure</h1>
<div class="note"><b>NOTE:</b> This section is considered "advanced" as it covers the technical appearance and structure of the phone. Reading this section is not suggested if you do not have experience writing HTML and CSS. It is intended as supplemental information when adding custom CSS.</div>
While the phone structure can be looked at in the install code (within your <nowiki>SugarPhone</nowiki> passage), a lot changes while the phone is in use. This section covers the dynamic elements especially and how they can be targeted for different needs.
To learn about choice formatting and structure, see the <a href="#structure-text-choice-box"><nowiki>#text-choice-box</nowiki> section</a>. To learn about the contact list, see the <a href="#structure-phone-contacts"><nowiki>#phone-contacts</nowiki> section</a>. To learn about chat structure and messages, see the <a href="#structure-chat-int"><nowiki>#chat-int</nowiki> section</a>.
<div class="note"><b>NOTE:</b> Use the sidebar setting toggles and your browser's inspector to see how the structure changes! Elements are generated differently or possess different classes based on those settings. Chat changes take effect the next time a chat is loaded.</div>
<<include "Phone Structure Index">>
<hr>
<h2 id="structure-default"><nowiki>
#phone
</nowiki></h2>
The phone's static HTML is in the <nowiki>SugarPhone</nowiki> passage. It is then acted upon by the various widgets and methods available to generate header content (e.g. alerts), the contact list, the chats, and the choices.
This entire element is wrapped by <nowiki>#phone-wrapper</nowiki>. It is refreshed after every passage transition during the <a href="https://www.motoslave.net/sugarcube/2/docs/#events-navigation-event-passagerender" target="_blank"><nowiki>:passagerender</nowiki> event</a>, if the phone is docked and visible. This means it can be changed via any <a href="https://www.motoslave.net/sugarcube/2/docs/#events-navigation" target="_blank">Navigation Events</a> that occur after <nowiki>:passagerender</nowiki>. (Links will open SugarCube documentation in a new tab.)
<pre><nowiki><div id="phone">
<div id="phone-header">
<div><<for _i = 0; _i < sp.getAlertCount(); _i++>><<=sp._getAlertIcon()>><</for>></div>
<div><<if Story.has("SugarPhone Head Centre")>><<include "SugarPhone Head Centre">><<else>><<powerlink>><</if>></div>
<div><<if Story.has("SugarPhone Head Right")>><<include "SugarPhone Head Right">><</if>></div>
</div>
<div id="phone-body">
<div id="text-app">
<div id="phone-contacts">
<<contactlist>>
</div>
<div id="chat">
<div id="loading"></div>
<div id="chat-int"></div>
</div>
</div>
<div id="text-choice-box-wrapper">
<div id="text-choice-box"></div>
</div>
</div>
</div></nowiki></pre>
<hr>
<h2 id="structure-phone-header"><nowiki>
#phone-header
</nowiki></h2>
The header contains three sections, two of which can contain custom content.
<h3>Code:</h3>
<pre><nowiki><div id="phone-header">
<div><<for _i = 0; _i < sp.getAlertCount(); _i++>><<=sp._getAlertIcon()>><</for>></div>
<div><<if Story.has("SugarPhone Head Centre")>><<include "SugarPhone Head Centre">><<else>><<powerlink>><</if>></div>
<div><<if Story.has("SugarPhone Head Right")>><<include "SugarPhone Head Right">><</if>></div>
</div></nowiki></pre>
In general, the header should contain simple information or links such as save/load links, time/date information, or icons to go with either.
Along with the rest of the phone, the user content sections are only updated after each passage transition unless the <nowiki><<updateheader>></nowiki> widget is used. Alerts are updated more frequently.
<div class="see"><b>SEE:</b> [[Adding to the Phone Header|Adding To Phone Header]].</div>
<h3>1. The Left</h3>
This section cannot have user content. It is used exclusively for alerts, which are floated to the left.
It is reloaded by <nowiki><<updatealerts>></nowiki>/<nowiki>sp.updateAlerts()</nowiki>, which trigger when the phone is opened or closed, when chats are added, loaded, branched, and ignored, and a number of other niche situations.
To target this element: <nowiki>#phone-header > div:first-of-type</nowiki>
<h3>2. The Centre</h3>
This will display the <nowiki>SugarPhone Head Centre</nowiki> passage in the centre of the header, ignoring line breaks. If the passage does not exist, this will display a <nowiki><<powerlink>></nowiki>.
You may want to put save, load, or other similar links here. Keeping a <nowiki><<powerlink>></nowiki> is highly suggested as players with small screens (i.e. mobile) may not be able to close the phone otherwise.
To target this element: <nowiki>#phone-header > div:nth-of-type(2)</nowiki>
<h4>Examples:</h4>
<pre><nowiki>:: SugarPhone Head Centre
<<powerlink>> | <<link "Saves">><<run UI.saves()>><</link>> | <<link "Restart">><<run UI.restart()>><</link>></nowiki></pre>
<h3>3. The Right</h3>
This will display the <nowiki>SugarPhone Head Right</nowiki> passage floated to the right, ignoring line breaks. If the passage does not exist, nothing is displayed.
You may want to put time, date, or other simple state-based information here.
To target this element: <nowiki>#phone-header > div:nth-of-type(3)</nowiki>
<h4>Examples:</h4>
<pre><nowiki>:: SugarPhone Head Right
$weekday $time</nowiki></pre>
<hr>
<h2 id="structure-phone-body"><nowiki>
#phone-body
</nowiki></h2>
This element contains everything apart from the header. When closed, nothing is displayed.
It has two child elements. The first (top) is the main <nowiki>#text-app</nowiki> that contains the contact list and the chat where texts appear. The second (bottom) is the <nowiki>#text-choice-box-wrapper</nowiki>, which contains text choices and text advance links.
This element does not change much and so little needs to be said.
<h3>Code:</h3>
<pre><nowiki><div id="phone-body">
<div id="text-app">
...
</div>
<div id="text-choice-box-wrapper">
...
</div>
</div></nowiki></pre>
<hr>
<h2 id="structure-text-app"><nowiki>
#text-app
</nowiki></h2>
This element is the core area of the opened phone. It does relatively little past acting as a container.
It contains two sections, one for the contact list and one for the chat.
<h3>Code:</h3>
<pre><nowiki><div id="text-app">
<div id="phone-contacts">
...
</div>
<div id="chat">
...
</div>
</div></nowiki></pre>
<h3 id="structure-phone-contacts">1. The Contact List (<nowiki>#phone-contacts</nowiki>)</h3>
This appears on the left and contains a list contacts who are not hidden and have at least one chat in their history.
This is populated with <nowiki><<contactlink>></nowiki> links by the <nowiki><<contactlist>></nowiki> widget automatically.
<h4>Contact Links</h4>
The structure of a contact link is as follows:
<pre><nowiki><div id="phone-contacts">
<div class="contact-row contactKey-row"><<link "Contact Name">><</link>></div>
</div></nowiki></pre>
This element supports per-contact styling for each row.
A contact's row can be targeted as follows: <nowiki>#phone-contacts .contactKey-row</nowiki>.
To target the link: <nowiki>#phone-contacts .contactKey-row a</nowiki>.
<h3>2. The Chat (<nowiki>#chat</nowiki>)</h3>
This appears on the right and contains the chat for any contact selected from the contact list. More information below.
<hr>
<h2 id="structure-chat"><nowiki>
#chat
</nowiki></h2>
This is the container for <nowiki>#chat-int</nowiki>, which contains dynamic content.
When a chat is loaded, <nowiki>#chat</nowiki> will have a case-sensitive, contact-specific class attached in the format <nowiki>contactKey-chat</nowiki>.
<h3>Examples:</h3>
<b>Chat loaded for the <nowiki>contactKey</nowiki> "Dad"</b>
<pre><nowiki><div id="chat" class="Dad-chat">
...chat stuff
</div></nowiki></pre>
<hr>
<h2 id="structure-loading"><nowiki>
#loading
</nowiki></h2>
This element is only visible when the chat is loading.
More specifically, it is visible when <nowiki>#phone</nowiki> has the class <nowiki>loading</nowiki>. This lasts from when a contact link is selected until <nowiki>$phone.config.chatLoadDelay</nowiki> (default: <nowiki>500</nowiki>) milliseconds has elapsed.
This prevents the chat from looking janky while content loads, especially if icons are being used. The slight delay can also give players the sense the phone is doing "work."
The loading gif/image can be set by ''altering'' the <nowiki>--loading-animation</nowiki> CSS variable.
<div class="see"><b>SEE:</b> <nowiki>$phone.config.chatLoadDelay</nowiki> in [[SugarPhone Settings]], CSS variables in [[Simple CSS]].</div>
<hr>
<h2 id="structure-chat-int"><nowiki>
#chat-int
</nowiki></h2>
This element is the direct parent of all dynamic chat content. As such, there are several parts to cover.
<div class="note"><b>NOTE:</b> This element does not contain choices. To see how choices are generated and styled, see <a href="#structure-text-choice-box"><nowiki>#text-choice-box</nowiki></a>.</div>
To start, we're going to look at what an example chat looks like before and after it's loaded into a chat.
<h3>The Chat:</h3>
<pre><nowiki>:: Example Chat One
<<send>>I'm a sent message<</send>>
<<receive>>I'm a received message<</receive>>
<<receive>>Straightforward stuff<</receive>>
<<send>>Definitely<</send>></nowiki></pre>
Assuming we've correctly added that chat to the phone, here is what the page looks like from <nowiki>#chat-int</nowiki> downward.
For a full perspective, we're going to assume icons are enabled and present, but the player has no icon defined. Back-to-back messages by the same contact omit names and icons.
<pre><nowiki><div id="chat-int">
...previous chats
<div class="text-wrapper sent">
<div class="contact-box">
<span class="contact-name">Player</span>
</div>
<div class="text">I'm a sent message</div>
</div>
<div class="text-wrapper received with-icon">
<div class="contact-box">
<span class="contact-name">Example</span>
<img src="contactIcon.png" title="" style="">
</div>
<div class="text">I'm a received message</div>
</div>
<div class="text-wrapper received after-icon">
<div class="text">Straightforward stuff</div>
</div>
<div class="text-wrapper sent">
<div class="contact-box">
<span class="contact-name">Player</span>
</div>
<div class="text">Definitely</div>
</div>
</div></nowiki></pre>
Let's go over this one piece at a time.
<h3><nowiki>.text-wrapper</nowiki></h3>
When you use the <nowiki><<send>></nowiki> and <nowiki><<receive>></nowiki> widgets, this is the top-level element they create. It is, unsurprisingly, the wrapper for each text, the associated names (if set and enabled), and their icons (if set and enabled).
Let's focus on just the first <nowiki><<receive>></nowiki> widget's output.
<pre><nowiki><div class="text-wrapper received with-icon">
<div class="contact-box">
<span class="contact-name">Example</span>
<img src="contactIcon.png" title="" style="">
</div>
<div class="text">I'm a received message</div>
</div></nowiki></pre>
The only difference between sent and received texts is the <nowiki>sent</nowiki> or <nowiki>received</nowiki> class. That governs whether a text will be floated to the right side of the chat or the left, respectively.
You'll also notice this has the class <nowiki>with-icon</nowiki>. That alters the formatting of <nowiki>contact-box</nowiki>, and it will only appear if icons are enabled.
If icons are enabled and repeats are disabled (suggested), subsequent messages have the class <nowiki>after-icon</nowiki>. You can see that on the second received message. That class allows these subsequent messages to align themselves with the <nowiki>with-icon</nowiki> messages.
In summary, there are <b>four</b> classes applied to <nowiki>text-wrapper</nowiki>. Either <nowiki>sent</nowiki> or <nowiki>receive</nowiki> will ALWAYS be present. Either <nowiki>with-icon</nowiki> or <nowiki>after-icon</nowiki> will be present if icons are enabled <b>and</b> the contact has an icon defined.
When used just to target the <nowiki>.text-wrapper</nowiki>, however, these selectors aren't very useful. It's only a container. Let's look its contents.
<div class="see"><b>SEE:</b> [[Group Chats]] for information on per-contact text styles in group chats.</div>
<h4><nowiki>.contact-box</nowiki></h4>
This contains the contact's name (in the case of <nowiki><<receive>></nowiki>), the player's name (in the case of <nowiki><<send>></nowiki>), or the explicitly passed name (in the case of both widgets), all of which are wrapped by a <nowiki><span></nowiki> with the class <nowiki>contact-name</nowiki>.
It also contains an icon, if icons are enabled and the contact (or player) has one defined.
<div class="note"><b>NOTE:</b> Depending on your [[SugarPhone Settings]], icons and names may appear with one another, alone, vice versa, or neither. If neither appear, the contact box will not be created.</div>
<pre><nowiki><div class="contact-box">
<span class="contact-name">Example</span>
<img src="contactIcon.png" title="" style="">
</div></nowiki></pre>
To target the name text for all contacts, we can use <nowiki>.text-wrapper .contact-name</nowiki>. We may want to get more specific, though.
Names that appear with icons: <nowiki>.with-icon .contact-name</nowiki>.
Names that appear with icons in sent messages: <nowiki>.sent.with-icon .contact-name</nowiki>.
Similarly, we can target the icons: <nowiki>.contact-box img</nowiki>. In this case, <nowiki>.with-icon</nowiki> never needs to be specified since it's only present when an <nowiki>img</nowiki> is.
In general, the <nowiki>.after-icon</nowiki> selector should be unnecessary when styling <nowiki>.contact-box</nowiki>.
<h4><nowiki>.text</nowiki></h4>
This element holds the contents of a given set of <nowiki><<send>></nowiki> or <nowiki><<receive>></nowiki> tags.
To target it, use <nowiki>.text-wrapper .text</nowiki>.
As with other elements, it can be more specific: <nowiki>.received .text</nowiki>.
<hr>
<h2 id="structure-text-choice-box-wrapper"><nowiki>
#text-choice-box-wrapper
</nowiki></h2>
This element is the wrapper for <nowiki>#text-choice-box</nowiki>, which in turn contains all prompts that occur during live chats.
<hr>
<h2 id="structure-text-choice-box"><nowiki>
#text-choice-box
</nowiki></h2>
This element contains all prompts that occur during live chats.
When a chat is live, this is what the element may contain.
<pre><nowiki><div id="text-choice-box">
<div id="text-choices" class="hide">
... Chat choice links
</div>
<a id="advance-text">→</a>
</div></nowiki></pre>
<h3><nowiki>#text-choices</nowiki></h3>
This element is generated by the <nowiki><<textchoice>></nowiki> and <nowiki><<textfinish>></nowiki> widgets (plus their variants) when a chat is ''live'' and the chat in question is the ''most recent''. It remains hidden until no texts remain to be seen. It does not exist otherwise.
The links it contains are regular <nowiki><<link>></nowiki> macros. They can be targeted via <nowiki>#text-choices a</nowiki>.
<h3><nowiki>#advance-text</nowiki></h3>
This element is generated automatically when a chat is ''live'' and ''at least'' one text remains to be seen. When no more texts remain to be seen, this element is removed.
It advances the chat when clicked.
It can be targeted via <nowiki>#text-choice-box a#advance-text</nowiki>.<h3>Phone Structure</h3>
<ul class="compact-list">
<li><a href="#structure-default"><nowiki>#phone</nowiki></a></li>
<li><a href="#structure-phone-header"><nowiki>#phone-header</nowiki></a></li>
<li><a href="#structure-phone-body"><nowiki>#phone-body</nowiki></a></li>
<li><a href="#structure-text-app"><nowiki>#text-app</nowiki></a></li>
<li><a href="#structure-phone-contacts"><nowiki>#phone-contacts</nowiki></a></li>
<li><a href="#structure-chat"><nowiki>#chat</nowiki></a></li>
<li><a href="#structure-loading"><nowiki>#loading</nowiki></a></li>
<li><a href="#structure-chat-int"><nowiki>#chat-int</nowiki></a></li>
<li><a href="#structure-text-choice-box-wrapper"><nowiki>#text-choice-box-wrapper</nowiki></a></li>
<li><a href="#structure-text-choice-box"><nowiki>#text-choice-box</nowiki></a></li>
</ul><h1>SugarPhone Widgets</h1>
When making changes to the phone, contacts, and chats, the phone's widgets are your best tool at getting these tasks done easily and safely.
For information about the state and history of the phone and its contacts, the [[SugarPhone API]] should be used.
<div class="note" id="widget-phone-only-note"><b>NOTE:</b> Widgets with an asterisk (*) beside them are not intended to be used outside of the phone. "Outside of the phone" means anything that does not appear exclusively in the phone's chat interface. Phone-only widgets rely on the phone being open and a chat being loaded when they appear.</div>
<<include "Widget Index">>
<h3 id="widget-add-contact"><nowiki>
<<addcontact contactKey [name] [iconSrc]>>
</nowiki></h3>
Define a textable contact.
The <nowiki>contactKey</nowiki> will be used to refer to this contact through all other widgets and methods.
<div class="see"><b>SEE:</b> <a href="#widget-update-contact"><nowiki><<updatecontact>></nowiki></a>, <nowiki>$phone.config.displayChatIcons</nowiki> in [[SugarPhone Settings]].</div>
<h4>Arguments:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: The unique case-sensitive string identifying a contact. Must follow the same rules as a variable name (e.g. no spaces, no special characters, etc.).</li>
<li><nowiki>name</nowiki>: (optional) The name you want a contact known by. If omitted, <nowiki>contactKey</nowiki> is used.</li>
<li><nowiki>iconSrc</nowiki>: (optional) The relative path to an image. A <nowiki>name</nowiki> must be defined when defining an icon.</li>
</ul>
<h4>Examples:</h4>
<b>Define a contact</b>
<pre><nowiki><<addcontact "Dad">></nowiki></pre>
<b>Define a contact with a long name</b>
<pre><nowiki><<addcontact "Earl" "The Earl of Torture">></nowiki></pre>
<b>Define a contact with a long name and an icon</b>
<pre><nowiki><<addcontact "tab" "Tabitha" "images/icons/tabitha.png">></nowiki></pre>
<hr>
<h3 id="widget-add-contact-group"><nowiki>
<<addcontactgroup contactKey [name] [iconSrc]>>
</nowiki></h3>
Define a textable contact group.
The <nowiki>contactKey</nowiki> will be used to refer to this contact through all other widgets and methods.
Contact groups require a <nowiki>contactKey</nowiki> whenever the <nowiki><<receive>></nowiki> widget is used in chats.
<div class="note"><b>NOTE:</b> While you can define an icon for group contacts, the only place it can appear is popup alerts.</div>
<div class="see"><b>SEE:</b> <a href="#widget-add-contact"><nowiki><<addcontact>></nowiki></a>, <a href="#widget-receive"><nowiki><<receive>></nowiki></a>, [[Group Chats]], <nowiki>$phone.config.popupAlerts</nowiki> in [[SugarPhone Settings]].</div>
<h4>Arguments:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: The unique case-sensitive string identifying a contact. Must follow the same rules as a variable name (e.g. no spaces, no special characters, etc.)</li>
<li><nowiki>name</nowiki>: (optional) The name you want a contact known by. If omitted, <nowiki>contactKey</nowiki> is used. This will only appear in the contact list and popup alerts (if enabled).</li>
<li><nowiki>iconSrc</nowiki>: (optional) The relative path to an image. A <nowiki>name</nowiki> must be passed when defining an icon. This will only appear in popup alerts (if enabled).</li>
</ul>
<h4>Examples:</h4>
<b>Define a contact group</b>
<pre><nowiki><<addcontactgroup "fam">></nowiki></pre>
<b>Define a contact group with a long name</b>
<pre><nowiki><<addcontactgroup "fam" "The Family Chat">></nowiki></pre>
<b>Define a contact group with a long name and an icon</b>
<pre><nowiki><<addcontactgroup "fam" "The Family Chat" "images/icons/family.png">></nowiki></pre>
<b>Writing contact group chats</b>
<pre><nowiki>:: fam Chat Group Chat Example
<<receive "Dad">>Received messages are different in group chats.<</receive>>
<<receive "Mom">>A valid contactKey MUST be passed to each receive widget<</receive>>
<<send>>But sent messages work the same as always<</send>>
<<receive "Dad" "dadman">>You can still specify per-message names, though!<</receive>>
<<receive "Dad">>Otherwise I go back to my defined name, "Dad"<</receive>>
<<tfinish>></nowiki></pre>
<hr>
<h3 id="widget-close-phone"><nowiki>
<<closephone>>
</nowiki></h3>
Closes the phone UI if it is currently open.
<div class="note"><b>NOTE:</b> The phone is closed automatically during passage transitions.</div>
<div class="see"><b>SEE:</b> <a href="#widget-lock-phone"><nowiki><<lockphone>></nowiki></a>, <a href="#widget-open-phone"><nowiki><<openphone>></nowiki></a>, <a href="#widget-toggle-phone"><nowiki><<togglephone>></nowiki></a>, <a href="#widget-unlock-phone"><nowiki><<unlockphone>></nowiki></a>.</div>
<h4>Examples:</h4>
<b>Link that can only close the phone</b>
<pre><nowiki><<link "Close Phone">>
<<closephone>>
<</link>></nowiki></pre>
<hr>
<h3 id="widget-ignore-all-chats"><nowiki>
<<ignoreallchats>>
</nowiki></h3>
Ends live chats and alerts for all contacts.
If ignored chat history is enabled (default), the ignored live chats are recorded.
<div class="note"><b>NOTE:</b> Using <nowiki><<lockphone>></nowiki> may be preferred when only needing to pause phone interactions.</div>
<div class="see"><b>SEE:</b> <a href="#widget-ignore-chat"><nowiki><<ignorechat>></nowiki></a>, <a href="#widget-lock-phone"><nowiki><<lockphone>></nowiki></a>, check ignore history via [[SugarPhone API]], <nowiki>$phone.config.disableIgnoredChatHistory</nowiki> in [[SugarPhone Settings]].</div>
<h4>Examples:</h4>
<b>Preventing chat rollover into new days</b>
<pre><nowiki><<link "Go to sleep" "Wake Up">>
<<set $day to $day + 1>>
<<ignoreallchats>>
<</link>></nowiki></pre>
<hr>
<h3 id="widget-ignore-chat"><nowiki>
<<ignorechat contactKey>>
</nowiki></h3>
Ends a specified contact's live chat and alert.
If ignored chat history is enabled (default), the ignored live chat is recorded. If the chat is inactive but an alert was set, the alert is ended and no record is made.
<div class="note"><b>NOTE:</b> Using <nowiki><<lockphone>></nowiki> may be preferred when only needing to pause phone interactions</div>
<div class="see"><b>SEE:</b> <a href="#widget-ignore-all-chats"><nowiki><<ignoreallchats>></nowiki></a>, <a href="#widget-lock-phone"><nowiki><<lockphone>></nowiki></a>, check ignore history via [[SugarPhone API]], <nowiki>$phone.config.disableIgnoredChatHistory</nowiki> in [[SugarPhone Settings]].</div>
<h4>Arguments:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: Unique key used to define the contact.</li>
</ul>
<h4>Examples:</h4>
<b>Ignore chats from scene-relevant contacts</b>
<pre><nowiki>:: Joshamy Date
<<ignorechat "josh">>
You and Joshamy hit the town for your highly anticipated date.
// If you know the text that may have been ignored, you can add flavour text
<<if sp.chatIgnored("Quick Question", "josh")>>
"Sorry for not getting back to you about that question," you say.
"It's ok, you still made it here!"
<</if>></nowiki></pre>
<hr>
<h3 id="widget-lock-phone"><nowiki>
<<lockphone [hide]>>
</nowiki></h3>
Closes the phone if it's open and locks it. The phone must be unlocked to be opened again.
<nowiki><<powerbutton>></nowiki> buttons and <nowiki><<powerlink>></nowiki> links are also visually updated.
<div class="see"><b>SEE:</b> <a href="#widget-close-phone"><nowiki><<closephone>></nowiki></a>, <a href="#widget-open-phone"><nowiki><<openphone>></nowiki></a>, <a href="#widget-power-btn"><nowiki><<powerbutton>></nowiki></a>, <a href="#widget-power-link"><nowiki><<powerlink>></nowiki></a>, <a href="#widget-toggle-phone"><nowiki><<togglephone>></nowiki></a>, <a href="#widget-unlock-phone"><nowiki><<unlockphone>></nowiki></a>.</div>
<h4>Arguments:</h4>
<ul>
<li><nowiki>hide</nowiki>: (optional) Should the phone be hidden when locked. Only applies to docked phones; un-docked phones are already hidden when closed.</li>
</ul>
<h4>Examples:</h4>
<b>Simple phone lock</b>
<pre><nowiki><<lockphone>></nowiki></pre>
<b>Phone lock and hide</b>
<pre><nowiki><<lockphone true>></nowiki></pre>
<hr>
<h3 id="widget-open-phone"><nowiki>
<<openphone>>
</nowiki></h3>
Opens the phone UI if it's currently closed and the phone is unlocked.
<div class="see"><b>SEE:</b> <a href="#widget-close-phone"><nowiki><<closephone>></nowiki></a>, <a href="#widget-lock-phone"><nowiki><<lockphone>></nowiki></a>, <a href="#widget-power-btn"><nowiki><<powerbutton>></nowiki></a>, <a href="#widget-power-link"><nowiki><<powerlink>></nowiki></a>, <a href="#widget-toggle-phone"><nowiki><<togglephone>></nowiki></a>, <a href="#widget-unlock-phone"><nowiki><<unlockphone>></nowiki></a>.</div>
<h4>Examples:</h4>
<b>Link that can only open the phone</b>
<pre><nowiki><<link "Open Phone">>
<<openphone>>
<</link>></nowiki></pre>
<hr>
<h3 id="widget-power-btn"><nowiki>
<<powerbutton [buttonText] [animateWhenLive]>>
</nowiki></h3>
A self-updating button with a power icon and an alert icon (if one or more alert is pending).
It will toggle the phone open and closed when clicked, if the phone is unlocked. If the phone is locked, the button will become greyed out and unusable and the power icon will become a lock icon.
This can be useful when you have an un-docked phone, especially when placed in the sidebar.
<div class="see"><b>SEE:</b> For a bare link without alerts or animations use <a href="#widget-power-link"><nowiki><<powerlink>></nowiki></a>, <nowiki>$phone.config.docked</nowiki> in [[SugarPhone Settings]].</div>
<h4>Arguments:</h4>
<ul>
<li><nowiki>buttonText</nowiki>: (optional) The text for the button to display. If omitted, "Toggle Phone" will be displayed.</li>
<li><nowiki>animateWhenLive</nowiki>: (optional) Should the button animate when any chat is live.</li>
</ul>
<h4>Examples:</h4>
<b>Button with the text "Toggle Phone" and no animations</b>
<pre><nowiki><<powerbutton>></nowiki></pre>
<b>Button with the text "Power" and no animations</b>
<pre><nowiki><<powerbutton "Power">></nowiki></pre>
<b>Button with the text "Toggle Phone" and animations when any chat is live</b>
<pre><nowiki><<powerbutton true>></nowiki></pre>
<b>Button with the text "Power" and animations when any chat is live</b>
<pre><nowiki><<powerbutton "Power" true>></nowiki></pre>
<hr>
<h3 id="widget-power-link"><nowiki>
<<powerlink [linkText]>>
</nowiki></h3>
A self-updating link that toggles the phone when clicked.
If the phone is locked, the link will become greyed out and unusable until the phone is unlocked. The power icon will also become a lock icon.
<div class="see"><b>SEE:</b> For a robust button with alerts and animations use <a href="#widget-power-btn"><nowiki><<powerbutton>></nowiki></a>.</div>
<h4>Arguments:</h4>
<ul>
<li><nowiki>linkText</nowiki>: (optional) The text for the link to display. If omitted, "Power" will be displayed.</li>
</ul>
<h4>Examples:</h4>
<b>Link with the text "Power"</b>
<pre><nowiki><<powerlink>></nowiki></pre>
<b>Link with the text "Phone"</b>
<pre><nowiki><<powerlink "Phone">></nowiki></pre>
<hr>
<h3 id="widget-receive"><<nobr>>
<nowiki><<receive [displayName]>>...<</receive>></nowiki><a href="#widget-phone-only-note">*</a><</nobr>>
<nowiki><<receive contactKey [displayName]>>...<</receive>></nowiki><a href="#widget-phone-only-note">*</a>
</h3>
A left-floated text message that may also display a contact's name and icon.
Line breaks are ignored unless a <nowiki><br></nowiki> element is used.
<div class="see"><b>SEE:</b> <a href="#widget-send"><nowiki><<send>></nowiki></a>, [[Group Chats]], [[SugarPhone Settings]] to change icon and name behaviour.</div>
<h4>Arguments:</h4>
<h4>Regular chat form:</h4>
<ul>
<li><nowiki>displayName:</nowiki> (optional) Name to appear above a text. If omitted, the contact's name will be used.</li>
</ul>
<h4>Group chat form:</h4>
<ul>
<li><nowiki>contactKey:</nowiki> Unique key used to define the contact.</li>
<li><nowiki>displayName:</nowiki> (optional) Name to appear above a text. If omitted, the contact's name will be used.</li>
</ul>
<h4>Examples (Regular Contact Use):</h4>
<b>Simple use</b>
<pre><nowiki><<receive>>Heya, what's up?<</receive>></nowiki></pre>
<b>One-off name change</b>
<pre><nowiki><<receive "Splarg">>Check out my weird name<</receive>>
<<send>>I'm gonna be honest, I hate it<</send>>
<<receive>>.......... fine<</receive>></nowiki></pre>
<b>Single message with line breaks</b>
<pre><nowiki><<receive>>This message will have no line breaks in the phone,
despite a line break in the text<</receive>>
<<receive>>This message will have a line break at the br element,<br>even when the text is on one line<</receive>></nowiki></pre>
<h4>Examples (Contact Group Use):</h4>
<b>Bad</b>
<pre><nowiki><<receive>>This has no contactKey, so this message will create an error<</receive>></nowiki></pre>
<b>Good</b>
<pre><nowiki><<receive "Dad">>This message has a contactKey, so it will behave as expected!<</receive>></nowiki></pre>
<b>One-off name change</b>
<pre><nowiki><<receive "Dad" "Daddio">>This message will display "Daddio" as my name<</receive>>
<<receive "Dad">>This goes back to the name associated with the contactKey "Dad"<</receive>></nowiki></pre>
<hr>
<h3 id="widget-receive-chat"><nowiki>
<<receivechat contactKey chatKey [chatLive]>>
</nowiki></h3>
Use for contact-initiated chats, which means a chat beginning with a <a href="#widget-receive"><nowiki><<receive>></nowiki></a> widget.
<div class="warning"><b>WARNING:</b> Chats are added indiscriminately with duplicate syntax (<nowiki>##chatKey</nowiki>), so ensure that it can only trigger under desired circumstances. Additionally, duplicates are considered a single chat in terms of choice and ignore history (when enabled)--only the most recent choice is recorded and ignoring any single duplicate will count for all. When ignore state is important, it may be preferable to use <nowiki><<removechat>></nowiki> and forego duplicate syntax.</div>
<div class="note"><b>NOTE:</b> <nowiki><<sendchat>></nowiki> and <nowiki><<receivechat>></nowiki> only function differently when <nowiki>chatLive</nowiki> is <nowiki>true</nowiki>.</div>
<div class="see"><b>SEE:</b> <a href="#widget-remove-chat"><nowiki><<removechat>></nowiki></a>, <a href="#widget-send-chat"><nowiki><<sendchat>></nowiki></a>.</div>
<h4>Arguments:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: Unique key used to define the contact.</li>
<li><nowiki>chatKey</nowiki>: Suffix for some chat passage. Begin the key with ## (e.g. <nowiki>##Reminder</nowiki>) to allow duplicates to be received.</li>
<li><nowiki>chatLive</nowiki>: (optional) When <nowiki>true</nowiki>, the chat will be live and an alert will be created.</li>
</ul>
<h4>Examples:</h4>
<b>Add an inactive chat</b>
<pre><nowiki><<receivechat "Mom" "Reminders">></nowiki></pre>
<b>Add a live chat</b>
<pre><nowiki><<receivechat "Dad" "Home Conversation" true>></nowiki></pre>
<b>Add a duplicate live chat</b>
<pre><nowiki>// Assumes $weekday is an array of weekday names
<<link "Sleep until tomorrow" "Wake Up">>
<<set $day to $day + 1>>
<<if $weekday[$day % 7] is "Monday">>
<<receivechat "Work" "##Shift Today" true>>
<</if>>
<</link>></nowiki></pre>
<hr>
<h3 id="widget-remove-chat"><nowiki>
<<removechat contactKey chatKey>>
</nowiki></h3>
Removes all instances of a <nowiki>chatKey</nowiki> and its related information for some contact.
If a contact's chat is live and the <nowiki>chatKey</nowiki> removed is the most recent chat, the chat will be made inactive during removal. Otherwise the chat will remain in its present state.
<div class="warning"><b>WARNING:</b> The <nowiki>chatKey</nowiki> will no longer exist in the contact's chat history. That means the choices and ignore state related to it will be wiped.</div>
<h4>Arguments:</h4>
<ul>
<li><nowiki>contactKey:</nowiki> Unique key used to define the contact.</li>
<li><nowiki>chatKey</nowiki>: Suffix for some chat passage.</li>
</ul>
<h4>Examples:</h4>
<pre><nowiki><<removechat "Dad" "Some Chat">></nowiki></pre>
<hr>
<h3 id="widget-remove-contact"><nowiki>
<<removecontact contactKey>>
</nowiki></h3>
Removes a contact and all related information.
<div class="warning"><b>WARNING:</b> The contact will no longer exist in any capacity. Do not delete a contact if you rely on chat history and choices outside of that contact's chat.</div>
<h4>Arguments:</h4>
<ul>
<li><nowiki>contactKey:</nowiki> Unique key used to define the contact.</li>
</ul>
<h4>Examples:</h4>
<pre><nowiki><<removecontact "Dad">></nowiki></pre>
<hr>
<h3 id="widget-send"><nowiki>
<<send [displayName]>>...<</send>>
</nowiki><a href="#widget-phone-only-note">*</a></h3>
A right-floated text message that may also display the player's name and icon.
Line breaks are ignored unless a <nowiki><br></nowiki> element is used.
<div class="see"><b>SEE:</b> <a href="#widget-receive"><nowiki><<receive>></nowiki></a>, [[SugarPhone Settings]] to change the player's name and icon as well as general name and icon behaviour.</div>
<h4>Arguments:</h4>
<ul>
<li><nowiki>displayName:</nowiki> (optional) Name to appear above a text.</li>
</ul>
<h4>Examples:</h4>
<b>Simple use</b>
<pre><nowiki><<send>>Hey, how's it going!<</send>></nowiki></pre>
<b>One-off name change</b>
<pre><nowiki><<send "sts d456">>Hey, how's it going?<</send>>
<<receive>>What's wrong with your name?<</receive>>
<<send>>Uh............ idk<</send>>
<<receive>>Oh, it's normal now<</receive>></nowiki></pre>
<b>Single message with line breaks</b>
<pre><nowiki><<send>>This message will have no line breaks in the phone,
despite a line break in the text<</send>>
<<send>>This message will have a line break at the br element,<br>even when the text is on one line<</send>></nowiki></pre>
<hr>
<h3 id="widget-send-chat"><nowiki>
<<sendchat contactKey chatKey [chatLive]>>
</nowiki></h3>
Use for player-initiated chats, which means a chat that begins with a <nowiki><<send>></nowiki> or <nowiki><<textchoice>></nowiki>/<nowiki><<tchoice>></nowiki>.
Because <nowiki><<sendchat>></nowiki> will open the phone when <nowiki>chatLive</nowiki> is <nowiki>true</nowiki>, it's highly suggested to execute it via player interaction, such as with a <nowiki><<link>></nowiki>.
<div class="warning"><b>WARNING:</b> Chats are added indiscriminately with duplicate syntax (<nowiki>##chatKey</nowiki>), so ensure that it can only trigger under desired circumstances. Additionally, duplicates are considered a single chat in terms of choice and ignore history (when enabled)--only the most recent choice is recorded and ignoring any single duplicate will count for all. When ignore state is important, it may be preferable to use <nowiki><<removechat>></nowiki> and forego duplicate syntax.</div>
<div class="note"><b>NOTE:</b> <nowiki><<sendchat>></nowiki> and <nowiki><<receivechat>></nowiki> only function differently when <nowiki>chatLive</nowiki> is <nowiki>true</nowiki>.</div>
<div class="see"><b>SEE:</b> <a href="#widget-receive-chat"><nowiki><<receivechat>></nowiki></a>, <a href="#widget-remove-chat"><nowiki><<removechat>></nowiki></a>.</div>
<h4>Arguments:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: Unique key used to define the contact.</li>
<li><nowiki>chatKey</nowiki>: Suffix for some chat passage. Begin the key with ## (e.g. <nowiki>##Reminder</nowiki>) to allow duplicates to be sent.</li>
<li><nowiki>chatLive</nowiki>: (optional) When <nowiki>true</nowiki>, the chat will be live and the phone will open.</li>
</ul>
<h4>Examples:</h4>
<b>Add an inactive chat</b>
<pre><nowiki><<sendchat "Friend" "ChatKey">></nowiki></pre>
<b>Add a live chat, which opens the phone</b>
<pre><nowiki><<link "Text your friend">>
<<sendchat "Friend" "Check In" true>>
<</link>></nowiki></pre>
<b>Add a duplicate live chat, which opens the phone</b>
<pre><nowiki><<link "Text your friend">>
<<sendchat "Friend" "##Check In" true>>
<</link>></nowiki></pre>
<hr>
<h3 id="widget-tchoice"><nowiki>
<<tchoice linkText chatKey>>
</nowiki><a href="#widget-phone-only-note">*</a></h3>
Creates a link that will continue the conversation to a specified chat. If you need to execute code, use <nowiki><<textchoice>></nowiki> instead.
<div class="see"><b>SEE:</b> <a href="#widget-text-choice"><nowiki><<textchoice>></nowiki></a>.</div>
<h4>Arguments:</h4>
<ul>
<li><nowiki>linkText</nowiki>: The text of the link. Works best as a summary or verbatim preview of the player's next text.</li>
<li><nowiki>chatKey</nowiki>: Suffix for some chat passage. Begin chat key with ## (e.g. <nowiki>##Reminder</nowiki>) to allow duplicates to be added.</li>
</ul>
<h4>Examples:</h4>
<b>Branching conversation</b>
<pre><nowiki><<receive>>Hey, can you hang out tomorrow?<</receive>>
<<textchoice "Yeah, I can" "Hang Out">><<set $eventPending = true>><</textchoice>>
<<tchoice "No, sorry" "No Hang Out">></nowiki></pre>
<b>Branching conversation to a duplicate chat</b>
<pre><nowiki><<receive>>It was fun seeing you today, but I've got to go sleep now<</receive>>
<<send>>Me too<</send>>
<<tchoice "Nighty Nighty" "##Good Night">></nowiki></pre>
<hr>
<h3 id="widget-text-alert"><nowiki>
<<textalert contactKey>>
</nowiki></h3>
Sets a contact alert ''without'' making a chat live. This can be useful to notify players of new texts that do not require interaction.
Alerts are unset the first time a contact's chat is opened in the phone. The ignore widgets can also unset alerts of inactive chats without recording them as ignored.
If popups are enabled, a popup will also be triggered for the most recent chat IF it contains a <nowiki><<receive>></nowiki> widget. The contents of the first <nowiki><<receive>></nowiki> is previewed.
<div class="see"><b>SEE:</b> <a href="#widget-receive-chat"><nowiki><<receivechat>></nowiki></a>, <a href="#widget-send-chat"><nowiki><<sendchat>></nowiki></a>, <nowiki>$phone.config.popupAlerts</nowiki> in [[SugarPhone Settings]].</div>
<h4>Arguments:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: Unique key used to define the contact.</li>
</ul>
<h4>Examples:</h4>
<b>Alert players to a new inactive chat</b>
<pre><nowiki><<receivechat "lisa" "Task Information">>
<<textalert "lisa">></nowiki></pre>
<hr>
<h3 id="widget-text-choice"><nowiki>
<<textchoice linkText chatKey>>...<</textchoice>>
</nowiki><a href="#widget-phone-only-note">*</a></h3>
Creates a link that will continue the conversation to a specified chat and execute its contents. Using <nowiki><<tchoice>></nowiki> is suggested when code execution is not required.
<div class="warning"><b>WARNING:</b> It's possible for players to miss clicking any given <nowiki><<textchoice>></nowiki> if their live chat is superseded by a new chat with that contact or an ignore widget runs. This means you should avoid executing essential game code with <nowiki><<textchoice>></nowiki> without precautions in place.</div>
<div class="see"><b>SEE:</b> <a href="#widget-tchoice"><nowiki><<tchoice>></nowiki></a>.</div>
<h4>Arguments:</h4>
<ul>
<li><nowiki>linkText</nowiki>: The text of the link. Works best as a summary or verbatim preview of the player's next text.</li>
<li><nowiki>chatKey</nowiki>: Suffix for some chat passage. Begin chat key with ## (e.g. <nowiki>##Reminder</nowiki>) to allow duplicates to be added.</li>
</ul>
<h4>Examples:</h4>
<b>Branching conversation</b>
<pre><nowiki><<receive>>how does thurs feel 4 u?<</receive>>
<<textchoice "Thurs works great for me!!" "Date Yes">><<set $eventPending = true>><</textchoice>>
<<tchoice "Sorry im busy thursday :(" "Date No">></nowiki></pre>
<b>Branching conversation to a duplicate chat</b>
<pre><nowiki><<receive>>It was fun seeing you today, but I've got to go sleep now<</receive>>
<<send>>Me too<</send>>
<<textchoice "Nighty Nighty" "##Good Night">><</textchoice>></nowiki></pre>
<hr>
<h3 id="widget-text-finish"><nowiki>
<<textfinish [linkText]>>...<</textfinish>>
</nowiki><a href="#widget-phone-only-note">*</a></h3>
A single-use link that closes the phone and executes its contents when clicked. If the chat is closed without clicking the link, it will not reappear.
Using <nowiki><<tfinish>></nowiki> is suggested when code execution is not required.
<div class="warning"><b>WARNING:</b> While the link will execute code, it should ''never'' be significant code as it can be missed very, very easily.</div>
<div class="note"><b>NOTE:</b> Do not use more than one in the same chat. Do not use in the same chat with <nowiki><<textchoice>></nowiki>, <nowiki><<tchoice>></nowiki>, or <nowiki><<tfinish>></nowiki>.</div>
<div class="see"><b>SEE:</b> <a href="#widget-tfinish"><nowiki><<tfinish>></nowiki></a>.</div>
<h4>Arguments:</h4>
<ul>
<li><nowiki>linkText</nowiki>: (optional) Text for the link to display. If omitted, "Close" will be displayed.</li>
</ul>
<h4>Examples:</h4>
<b>Link with the text "Close" that closes the phone and sets a variable</b>
<pre><nowiki><<receive>>See ya!<</receive>>
<<send>>See ya!<</send>>
<<textfinish>><<set $foo = "bar">><</textfinish>></nowiki></pre>
<b>Link with the text "Bed time" that closes the phone and sets a variable</b>
<pre><nowiki><<receive>>See ya!<</receive>>
<<send>>See ya!<</send>>
<<textfinish "Bed time">><<set $foo = "bar">><</textfinish>></nowiki></pre>
<hr>
<h3 id="widget-tfinish"><nowiki>
<<tfinish [linkText]>>
</nowiki><a href="#widget-phone-only-note">*</a></h3>
A single-use link that closes the phone when clicked. If the chat is closed without clicking the link, it will not reappear.
If you need to execute code with this link, use <nowiki><<textfinish>></nowiki> instead.
<div class="note"><b>NOTE:</b> Do not use more than one in the same chat. Do not use in the same chat with <nowiki><<textchoice>></nowiki>, <nowiki><<tchoice>></nowiki>, or <nowiki><<textfinish>></nowiki>.</div>
<div class="see"><b>SEE:</b> <a href="#widget-text-finish"><nowiki><<textfinish>></nowiki></a>.</div>
<h4>Arguments:</h4>
<ul>
<li><nowiki>linkText</nowiki>: (optional) Text you wish to display instead of "Close" on the link.</li>
</ul>
<h4>Examples:</h4>
<b>Link with the text "Close" that closes the phone</b>
<pre><nowiki><<receive>>See ya!<</receive>>
<<send>>See ya!<</send>>
<<tfinish>></nowiki></pre>
<b>Link with the text "Bed time" that closes the phone</b>
<pre><nowiki><<receive>>See ya!<</receive>>
<<send>>See ya!<</send>>
<<tfinish "Bed time">></nowiki></pre>
<hr>
<h3 id="widget-toggle-phone"><nowiki>
<<togglephone>>
</nowiki></h3>
Toggles the phone open or closed, depending on its state.
<div class="see"><b>SEE:</b> <a href="#widget-close-phone"><nowiki><<closephone>></nowiki></a>, <a href="#widget-lock-phone"><nowiki><<lockphone>></nowiki></a>, <a href="#widget-open-phone"><nowiki><<openphone>></nowiki></a>, <a href="#widget-unlock-phone"><nowiki><<unlockphone>></nowiki></a>.</div>
<h4>Examples:</h4>
<b>Link that opens and closes the phone, if it's not locked</b>
<pre><nowiki><<link "Toggle Phone">>
<<togglephone>>
<</link>></nowiki></pre>
<hr>
<h3 id="widget-unlock-phone"><nowiki>
<<unlockphone>>
</nowiki></h3>
Allows the phone to be opened and the UI will return to its regular closed state.
<nowiki><<powerbutton>></nowiki> buttons and <nowiki><<powerlink>></nowiki> links will also visually update and become usable again.
<div class="see"><b>SEE:</b> <a href="#widget-close-phone"><nowiki><<closephone>></nowiki></a>, <a href="#widget-lock-phone"><nowiki><<lockphone>></nowiki></a>, <a href="#widget-open-phone"><nowiki><<openphone>></nowiki></a>, <a href="#widget-toggle-phone"><nowiki><<togglephone>></nowiki></a>.</div>
<h4>Examples:</h4>
<pre><nowiki><<unlockphone>></nowiki></pre>
<hr>
<h3 id="widget-update-alerts"><nowiki>
<<updatealerts>>
</nowiki></h3>
Update all alerts in the phone header and <nowiki><<powerbutton>></nowiki> buttons. If the phone is open, the contact list is also reloaded.
In general, this doesn't need to be called manually but doing so is harmless if you need to force update alerts or the contact list.
Use <nowiki><<updateheader>></nowiki> to update the header's other sections.
<div class="note"><b>NOTE:</b> SugarPhone updates alerts when the phone is opened or closed, when chats are added, loaded, branched, and ignored, and a number of other niche situations.</div>
<div class="see"><b>SEE:</b> <a href="#widget-update-header"><nowiki><<updateheader>></nowiki></a>.</div>
<h4>Examples:</h4>
<pre><nowiki><<updatealerts>></nowiki></pre>
<hr>
<h3 id="widget-update-contact"><nowiki>
<<updatecontact contactKey propertyName propertyValue>>
</nowiki></h3>
Update specific properties for a contact.
<div class="see"><b>SEE:</b> <a href="#widget-add-contact"><nowiki><<addcontact>></nowiki></a>, <a href="#widget-add-contact-group"><nowiki><<addcontactgroup>></nowiki></a>, <a href="#widget-remove-contact"><nowiki><<removecontact>></nowiki></a>.</div>
<h4>Arguments:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: Unique key used to define the contact.</li>
<li><nowiki>propertyName</nowiki>: The name of the property to change. Valid names: name; icon; display.</li>
<li><nowiki>propertyValue</nowiki>: The value for the property to be set to.</li>
</ul>
<h4>Examples:</h4>
<b>Update a name</b>
<pre><nowiki><<updatecontact "dany" "name" "Danylicious">></nowiki></pre>
<b>Update an icon</b>
<pre><nowiki><<updatecontact "dany" "icon" "images/icons/dany.png">></nowiki></pre>
<b>Hide a contact in the phone's contact list</b>
<pre><nowiki><<updatecontact "dany" "display" false>></nowiki></pre>
<hr>
<h3 id="widget-update-header"><nowiki>
<<updateheader>>
</nowiki></h3>
Update the header's custom content divs if their optional passages exist.
The optional passages are <nowiki>SugarPhone Head Centre</nowiki> and <nowiki>SugarPhone Head Right</nowiki>.
<div class="note"><b>NOTE:</b> The phone's header updates fully during passage transitions, so this widget should only be necessary if custom content needs more frequent updates.</div>
<div class="see"><b>SEE:</b> [[Adding to the Phone Header|Adding To Phone Header]].</div>
<h4>Examples:</h4>
<b>Update the header after changing a variable it displays</b>
<pre><nowiki><<link "Pass the time [1h]">>
<<set $time += 1>>
<<updateheader>>
<</link>></nowiki></pre><h3>Widgets</h3>
<ul class="compact-list">
<li><a href="#widget-add-contact"><nowiki><<addcontact>></nowiki></a></li>
<li><a href="#widget-add-contact-group"><nowiki><<addcontactgroup>></nowiki></a></li>
<li><a href="#widget-close-phone"><nowiki><<closephone>></nowiki></a></li>
<li><a href="#widget-ignore-all-chats"><nowiki><<ignoreallchats>></nowiki></a></li>
<li><a href="#widget-ignore-chat"><nowiki><<ignorechat>></nowiki></a></li>
<li><a href="#widget-lock-phone"><nowiki><<lockphone>></nowiki></a></li>
<li><a href="#widget-open-phone"><nowiki><<openphone>></nowiki></a></li>
<li><a href="#widget-power-btn"><nowiki><<powerbutton>></nowiki></a></li>
<li><a href="#widget-power-link"><nowiki><<powerlink>></nowiki></a></li>
<li><a href="#widget-receive"><nowiki><<receive>></nowiki>*</a></li>
<li><a href="#widget-receive-chat"><nowiki><<receivechat>></nowiki></a></li>
<li><a href="#widget-remove-chat"><nowiki><<removechat>></nowiki></a></li>
<li><a href="#widget-remove-contact"><nowiki><<removecontact>></nowiki></a></li>
<li><a href="#widget-send"><nowiki><<send>></nowiki>*</a></li>
<li><a href="#widget-send-chat"><nowiki><<sendchat>></nowiki></a></li>
<li><a href="#widget-tchoice"><nowiki><<tchoice>></nowiki>*</a></li>
<li><a href="#widget-text-alert"><nowiki><<textalert>></nowiki></a></li>
<li><a href="#widget-text-choice"><nowiki><<textchoice>></nowiki>*</a></li>
<li><a href="#widget-text-finish"><nowiki><<textfinish>></nowiki>*</a></li>
<li><a href="#widget-tfinish"><nowiki><<tfinish>></nowiki>*</a></li>
<li><a href="#widget-toggle-phone"><nowiki><<togglephone>></nowiki></a></li>
<li><a href="#widget-unlock-phone"><nowiki><<unlockphone>></nowiki></a></li>
<li><a href="#widget-update-alerts"><nowiki><<updatealerts>></nowiki></a></li>
<li><a href="#widget-update-contact"><nowiki><<updatecontact>></nowiki></a></li>
<li><a href="#widget-update-header"><nowiki><<updateheader>></nowiki></a></li>
</ul>
<hr><h1>SugarPhone Demo</h1>
Hello and welcome to the SugarPhone demo! This demo will walk you through the core features necessary to get your first branching chat up and running following [[installation|Installation]].
If you're just looking for quick reference code, see the [[quick start code samples|Quick Start]] page or the [[widget|Phone Widget Documentation]] and [[API|SugarPhone API]] documentation pages.
It must be emphasized that while this system is aimed to be as accessible as possible, it will likely be difficult to use if you are still learning the SugarCube ropes. If you've used custom macros and content before, you're probably off to a good start!
You're welcome to open up the phone now and poke around since it contains a few inactive conversations.
When you're done, we can get started on the step of the demo:
[[Defining a contact|Demo Add Contact]]<h1>Defining A Contact</h1>
All phone interactions come back to your ''contacts''. Before a contact can be chatted with, they must be defined with the <nowiki><<addcontact>></nowiki> widget.
We're going to assume contacts are being defined in the <a href="https://www.motoslave.net/sugarcube/2/docs/#special-passage-storyinit" target="_blank">StoryInit special passage</a> (link opens SC2 docs in a new tab), and that the first contact we want to add is "Dad".
<div class="note"><b>NOTE:</b> While it's easiest to define your contact in <nowiki>StoryInit</nowiki>, contacts can be added at any time. If <nowiki><<addcontact>></nowiki> tries to add an existing contact, it will be passed by, so there's no worries about overwriting your contacts.</div>
<pre><nowiki><<addcontact "Dad">></nowiki></pre>
Congrats! "Dad" can now be texted, though they won't show up in the phone's contact list until at least one ''chat'' has been added.
"Dad" can also be updated at any time, in case we want a longer name. Naturally, the <nowiki><<updatecontact>></nowiki> widget is used for this task.
<pre><nowiki><<updatecontact "Dad" "name" "Dadderino">></nowiki></pre>
As you can see, you just specify the contact, the property, and the new value! Other properties you can update are "icon" and "display".
The player does not have a name by default (and it's fine to leave it that way), but it can be set through the phone's settings. We won't look too closely at the settings, though, just the <nowiki>playerName</nowiki> property.
<pre><nowiki><<set $phone.config.playerName = "Player">></nowiki></pre>
Now both "Dad" and the player have a name to display in chats, but what is a "chat" more specifically?
[[Let's find out|Demo Chat Intro]]<h1>Chats</h1>
A ''chat'', in the context of SugarPhone, is a passage with a special name format. Here's the passage name of our first chat with "Dad":
<pre><nowiki>Dad Chat Introduction</nowiki></pre>
While " Chat " (spaces included) is a constant for the purposes of this demo, the two key variables are on either side: 1) the <nowiki>contactKey</nowiki> ("Dad") and 2) the <nowiki>chatKey</nowiki> ("Introduction").
<div class="note"><b>NOTE:</b> The chat name infix (" Chat ") can be changed in [[SugarPhone Settings]]. All sample code in the demo and documentation assumes the default is used.</div>
As you can see from our <nowiki><<addcontact "Dad">></nowiki> call, the <nowiki>contactKey</nowiki> was the first argument passed to the widget, and, like all passage names, it is case sensitive. While the <nowiki>contactKey</nowiki> can double as the contact's name, it's best as something you'll find quick to type and remember.
The <nowiki>chatKey</nowiki>, on the other hand, is entirely up to you. So long as it's valid in a passage name, it's valid as a <nowiki>chatKey</nowiki>. Any time you want to refer to this chat you'll need this key, so use whatever system makes sense to you.
With this information about <nowiki><<addcontact>></nowiki>, <nowiki><<updatecontact>></nowiki>, and the chat name format, we can learn about adding our first chat!
<div class="note"><b>NOTE:</b> You'll have seen a few words and phrases bolded or emphasized (such as <nowiki>contactKey</nowiki> and <nowiki>chatKey</nowiki>) so far; many of those are ''key terms''. You can find a refresher anytime in the [[Key Terms]] section.</div>
[[Let's give it a try|Demo Add Chat]]<h1>Adding Chats</h1>
Chats do not become a part of a contact's ''chat history'' until they are explicitly added, and the way to do that outside of the phone is with the <nowiki><<receivechat>></nowiki> and <nowiki><<sendchat>></nowiki> widgets.
Those widgets behave identically when adding a chat to the history, but they have a key difference when initiating ''live'' chats.
<div class="note"><b>NOTE:</b> In the context of SugarPhone, a ''live'' chat is one that requires player interaction to progress. Only a contact's most recent chat can be live, but multiple contacts can have live chats in progress.</div>
To state the obvious, <nowiki><<receivechat>></nowiki> should be used to initiate live chats when the first message is ''received'' by the player and <nowiki><<sendchat>></nowiki> should be used to initiate live chats when the first message is ''sent'' by the player.
Let's see what that looks like in action.
<<link "ReceiveChat Demo" "Demo Receive Chat">><<removechat "Dad" "Receive Introduction">><<receivechat "Dad" "Receive Introduction" true>><</link>>
[[SendChat Demo|Demo Send Chat]]<h1>Receiving Chats</h1>
Upon arriving here, you may already notice something different about the phone! There should be an alert in the header (if not, hit the reset link down the page and the code will refresh).
Feel free to open up the phone and engage with that chat, then we can look at the code below. This is the code that brought you to this passage.
<pre><nowiki>// Regular SugarCube <<link>> that executes the <<receivechat>> widget when clicked
<<link "Receive Dad's intro" "Demo Receive Chat">>
<<receivechat "Dad" "Receive Introduction" true>>
<</link>></nowiki></pre>
While you should recognize the first two arguments of <nowiki><<receivechat>></nowiki> (the <nowiki>contactKey</nowiki> and the <nowiki>chatKey</nowiki>), the third one is what makes this widget behave differently from <nowiki><<sendchat>></nowiki>.
When the third <i>optional</i> argument, <nowiki>chatLive</nowiki>, is present and <nowiki>true</nowiki> the contact's chat will be flagged as live and an alert will appear in the phone's header and a limited number of other places.
If you've opened the phone, you'll have seen that Dad's chat link is one of those places with an alert!
Click the link below if you'd like to reset the demo chat.
<<link "Reset Receive Chat Demo">><<removechat "Dad" "Receive Introduction">><<receivechat "Dad" "Receive Introduction" true>><</link>>
<div class="note"><b>NOTE:</b> While all alerts for a contact will be cleared the first time their chat is opened, the chat will remain live until the text chain is completed or the chat is ignored (more details on that later). This means players can switch open chats or open/close the phone without ending a conversation.</div>
Check out the <nowiki><<sendchat>></nowiki> demo to see its differences. If you've already seen it, proceed to the summary.
[[SendChat Demo|Demo Send Chat]]
[[Adding chats in summary|Demo Send Receive Summary]]<h1>Sending Chats</h1>
To send a chat, click the button below. When clicked, it's going to open the phone and you should notice one of the contact links pulsing.
<<link "Send a chat">><<removechat "Dad" "Send Introduction">><<sendchat "Dad" "Send Introduction" true>><</link>>
Once you're done, we can take a look at the code of that link:
<pre><nowiki>// Regular SugarCube <<link>> that executes <<sendchat>> when clicked
<<link "Send a chat">>
<<sendchat "Dad" "Send Introduction" true>>
<</link>></nowiki></pre>
While you should recognize the first two arguments of <nowiki><<sendchat>></nowiki> (the <nowiki>contactKey</nowiki> and the <nowiki>chatKey</nowiki>), the third one is what makes this widget behave differently from <nowiki><<receivechat>></nowiki>.
When the third <i>optional</i> argument, <nowiki>chatLive</nowiki>, is present and <nowiki>true</nowiki> the contact's chat will be flagged as live and the phone will open.
The automatic opening of the phone is why we wrapped <nowiki><<sendchat>></nowiki> in a <nowiki><<link>></nowiki>. This makes it easier for players to initiate a conversation.
Click the first link above to run the demo again.
Check out the <nowiki><<receivechat>></nowiki> demo to see its differences. If you've already seen it, proceed to the summary.
<<link "ReceiveChat Demo" "Demo Receive Chat">><<removechat "Dad" "Receive Introduction">><<receivechat "Dad" "Receive Introduction" true>><</link>>
[[Adding chats in summary|Demo Send Receive Summary]]<h1>Adding Chats in Summary</h1>
<nowiki><<receivechat>></nowiki> and <nowiki><<sendchat>></nowiki> can be used to add chats to the chat history and to start new live chats.
Their difference lies in how they trigger live chats, which happens when their third <i>optional</i> argument, <nowiki>chatLive</nowiki>, is <nowiki>true</nowiki>.
<nowiki><<receivechat>></nowiki> sets an alert, and that alert will appear in the phone's header and following the contact's name in the contact list. The contact link will be animated until the chat ends. Clicking the contact link unsets the alert.
<nowiki><<sendchat>></nowiki> opens the phone and the contact's link will be animated until the chat ends.
Multiple contacts can have live chats, but only the most recent chat for any given contact will be live. If you add a new chat when a live chat is pending, the previous chat will be considered ignored.
<b>Adding inactive chats</b>
<pre><nowiki><<receivechat "Dad" "Introduction" >> /* Adds an inactive chat to the history */
<<sendchat "Dad" "Introduction">> /* ALSO adds an inactive chat to the history */</nowiki></pre>
<b>Adding live chats</b>
<pre><nowiki><<receivechat "Dad" "Live Receive Demo" true>> /* Adds a live chat and creates a phone header notification */
<<sendchat "Dad" "Live Send Demo" true>> /* ALSO adds a live chat, but the phone is opened instead of creating notifications */</nowiki></pre>
You can test the above live chat code with the links below. Click the links again to reset.
<div class="note"><b>NOTE:</b> <nowiki><<sendchat>></nowiki> and <nowiki><<receivechat>></nowiki> only work once by default. This demo makes use of <nowiki><<removechat>></nowiki> to reset its examples. Without it (as it appears in the example code), clicking the links or adding the same chat more than once will cause nothing to happen.</div>
<<link "Receive live chat">><<removechat "Dad" "Live Receive Demo">><<receivechat "Dad" "Live Receive Demo" true>><</link>>
<<link "Send live chat">><<removechat "Dad" "Live Send Demo">><<sendchat "Dad" "Live Send Demo" true>><</link>>
When you're done, we'll take a [[closer look at a chat's structure|Demo Chat Structure]]<h1>Chat Structure</h1>
To make things simple we're going to look at the code directly from the first receive chat demo.
Here we can see the chat initiated by Dad, which is in the passage "Dad Chat Receive Introduction":
<pre><nowiki>// Reminder, this was added by calling <<receivechat "Dad" "Receive Introduction" true>>
:: Dad Chat Receive Introduction
<<receive>>Hey, how's it going sport?<</receive>>
<<send>>It's going great, dad.<</send>>
<<send>>Thanks for asking<</send>>
<<receive>>Anytime, slugger<</receive>></nowiki></pre>
Looks simple, right? No fancy arguments, no specifying contact or chat keys. Just two widgets that must enclose our sent and received messages, and they're aptly named <nowiki><<send>></nowiki> and <nowiki><<receive>></nowiki>.
Anything surrounded by the <nowiki><<send>></nowiki> widget will be floated to the right and have the player's name attached to it. Anything surrounded by the <nowiki><<receive>></nowiki> widget will be floated to the left and have the active contact's name above it (in this case, Dad).
With that under our belt, we can get to the real good part: <<link "Branching Chats" "Demo Branching Chats">><<receivechat "Dad" "Branching Demo" true>><</link>><h1>Branching Chats</h1>
Arriving here, you should have another alert in the phone's header. If not--or if you would like to run the branching chat demo again--hit the reset button below.
<<link "Reset Branching Demo">><<removechat "Dad" "Branching Demo">><<removechat "Dad" "Branching Bad">><<removechat "Dad" "Branching Good">><<receivechat "Dad" "Branching Demo" true>><</link>>
<pre><nowiki>:: Dad Chat Branching Demo
<<receive>>Hey, how's it going, sport<</receive>>
<<textchoice "Havin' a bad time, pops" "Branching Bad">><<set $dadLove = 1>><</textchoice>>
<<tchoice "It's going great, dad" "Branching Good">></nowiki></pre>
To branch our chats, you can see we have two new widgets. They are <nowiki><<textchoice>></nowiki> and <nowiki><<tchoice>></nowiki>, and they can be thought of as siblings to the <nowiki><<link>></nowiki> macro.
Just like with <nowiki><<link>></nowiki>, our first argument is the <b>linkText</b>, and much like <nowiki><<link>></nowiki> our second argument is the destination. Except instead of going to a new passage, we want to go to a new branch of the conversation. Both arguments are <b>required</b>.
While the <nowiki>linkText</nowiki> can be whatever you like (a preview of the player's next message being highly suggested), the destination <b>must</b> be a valid <nowiki>chatKey</nowiki> for the active contact.
With that said, we can see there are differences between those two widgets.
The more verbose <nowiki><<textchoice>></nowiki> can execute code--and as such, requires a closing tag--while the lightweight <nowiki><<tchoice>></nowiki> needs no closing tag.
In general, <nowiki><<tchoice>></nowiki> should be your go-to, especially when considering that any code executed by your text choice links may not happen when you think they should happen. Players love doing things at the worst possible moment.
<div class="note"><b>NOTE:</b> If you need more information and examples, make sure to check the documentation for both of these widgets.</div>
Now that we've made it this far, there's only one thing left to do: [[finish the chat|Demo Finish Chat]]<h1>Finishing Chats</h1>
If you played through the branching conversation demo, you'll have noticed that the chats ended with one last button that said "Close".
This is not essential, but it provides a clear signal to players that the conversation is over and that the phone will be closed once clicked.
You can run the demo again with this reset button:
<<link "Reset Branching Demo">><<removechat "Dad" "Branching Demo">><<removechat "Dad" "Branching Bad">><<removechat "Dad" "Branching Good">><<receivechat "Dad" "Branching Demo" true>><</link>>
Now here's the code from the good branch:
<pre><nowiki>:: Dad Chat Branching Good
<<send>>It's going great, dad<</send>>
<<receive>>I'm glad to hear that!<</receive>>
<<tfinish>></nowiki></pre>
You'll see one last widget here: <nowiki><<tfinish>></nowiki>. It acts as a ''one time'' link to exit a conversation and it will not reappear even if the link goes unclicked.
The <nowiki>linkText</nowiki> can be changed by passing it a string: <nowiki><<tfinish "My New Link Text">></nowiki>.
Similar to <nowiki><<tchoice>></nowiki> and <nowiki><<textchoice>></nowiki>, <nowiki><<textfinish>></nowiki> can be used instead of <nowiki><<tfinish>></nowiki> to execute code when clicked, but because of its one-time nature--and how easy it is to miss--it should not be necessary in most cases.
Nevertheless, the above code could be changed to use <nowiki><<textfinish>></nowiki> and set a variable when clicked.
<pre><nowiki>:: Dad Chat Branching Good
<<send>>It's going great, dad<</send>>
<<receive>>I'm glad to hear that!<</receive>>
<<textfinish>><<set $foo = bar>><</textfinish>></nowiki></pre>
And with that, we've covered all the essentials of SugarPhone. That only scratches the surface, however. The links in the sidebar can lead you to more sample code, sections on specific topics, and the formal documentation for all of the phone's widgets and API.
If you would like an introduction to the phone's API, [[you can start it here|Demo SugarPhone API Intro]]. The API provides information on choices made, chats ignored, chats had, and more.
If you would like a summary of all the widgets covered so far with example code, [[you can see it here|Demo Summary]].<h1>SugarPhone API Intro</h1>
So far, all you've seen about SugarPhone is its widgets. The widgets are for making things //happen//--whether that's sending a chat, opening the phone, or branching a chat.
But what about when you want to know what //has happened//? Well, that's where the ''SugarPhone API'' comes in.
To use the API, we must go through an instance of SugarPhone, <nowiki>sp</nowiki> (short of SugarPhone!). This makes its methods accessible without cluttering up the story history.
<div class="note"><b>NOTE:</b> <nowiki>sp</nowiki> is a global JavaScript object. It does ''not'' need to be prefixed with a sigil (<nowiki>$</nowiki>).</div>
Let's use a quick example:
<pre><nowiki><<if sp.contactExists("Dad")>>
Dad has been added to the phone.
<<else>>
Dad has not been added to the phone.
<</if>></nowiki></pre>
Not much to it, huh? There's over a dozen methods you can use, and they can all be used similar to above. Let's add a couple quick examples for methods you may want to use most:
<b>Check if a chat was ignored</b>
<pre><nowiki><<if sp.chatIgnored("Introduction", "Dad")>>
You ignored the chat with "Dad" with the chatKey "Introduction"
<</if>></nowiki></pre>
<b>Check if a chat exists in a contact's chat history</b>
<pre><nowiki><<if sp.hadChat("Dad", "Some Chat")>>
Dad's chat history includes the chatKey "Some Day"
<</if>></nowiki></pre>
<b>Check which choice was made in a specific contact's chat</b>
<pre><nowiki><<if sp.choiceMadeIn("Important Decision", "Dad") is 1>>
The second text choice was selected in Dad's "Important Decision" chat.
This number is 0-indexed, so the first choice is 0 and the third is 2.
<</if>></nowiki></pre>
It's OK if you don't quite get what those methods are doing, though you probably get the jist. What's important is that you understand how these methods are accessed.
If you want to know more about the SugarPhone API, you have several options.
[[Documentation: SugarPhone API|SugarPhone API]]
[[Quick Start Code Samples|Quick Start]]
[[Topic: Checking Choices|Checking Choices]]
[[Topic: Ignoring Chats|Ignoring Chats]]
All the above links can also be accessed through the index in the sidebar.
If you would like a summary of all the widgets covered so far with example code, [[you can see it here|Demo Summary]].<h1>Summary</h1>
With this demo done, I hope using SugarPhone makes sense to you! There are more features that were not covered, and other uses for the phone that are supported.
We'll summarize here by showing one last piece of example code, from contact definition to finishing their first branching conversation.
<div class="note"><b>NOTE:</b> The example below (and elsewhere in the documentation) uses <a href="https://twinery.org/cookbook/terms/terms_twee.html" target="_blank">Twee notation</a> (link opens the Twine Cookbook in new tab). In Twee notation, passage names are denoted by a double colon ("::") and their content is everything that follows until the next passage name.</div>
<pre><nowiki> :: StoryInit
<<addcontact "Dad" "Dadderino">> → add a contact with the display name "Dadderino"
:: Day One
It's time of go on an exciting adventure. You should let your dad know before you go.
/* Trigger a live chat and open the phone when clicked */
<<link "Text dad">>
<<sendchat "Dad" "Off To Adventure" true>>
<</link>>
@@.leave;When you done, it's time to head out.@@
<<link "Leave">>
/* Returns true if Dad's chat history contains either of these chat keys */
/* This ensures the text conversation was finished without caring how */
<<if sp.hadChat("Dad", "Adventure EndA", "Adventure EndB")>>
<<goto "Next Passage">>
<<else>>
/* Replace the text above with an additional prompt to use the phone */
<<replace ".leave">>You should finish texting Dad before you leave.<</replace>>
<</if>>
<</link>>
:: Dad Chat Off To Adventure
<<send>>Hey dad, just so you know I'm heading off an adventure<</send>>
<<receive>>Woahhh, crazy<</receive>>
<<receive>>Be careful<</receive>>
<<tchoice "I'll think about it" "Adventure EndA">>
/* Use the full <<textchoice>> widget to execute code */
<<textchoice "I will, thanks dad" "Adventure EndB">>
<<set $dadAffection += 1>>
<</textchoice>>
:: Dad Chat Adventure EndB
<<send>>I will, thanks dad<</send>>
<<receive>>Good to hear that.<</receive>>
<<receive>>Good luck<</receive>>
/* Optional close button that says "Off to Adventure" */
<<tfinish "Off to Adventure">></nowiki></pre>
I hope that all makes sense! Feel free to jump into the rest of the documentation and guides via the links in the sidebar, or get started right away on your game and check out the more advanced or specific features as you need them, if you do at all.
If you would like an introduction to the phone's API, [[you can start it here|Demo SugarPhone API Intro]]. The API can provide information on choices made, chats ignored, chats had, and more.
Otherwise, you can [[return home|Start]]<h1>Installation</h1>
You have two options when it comes to SugarPhone installation.
If you're starting a brand new project, you can import the template project. It has everything set up already.
If you're adding SugarPhone to an existing project, you will need to install the code to the correct locations (instructions below). If you're having trouble, you can import the template project and look at how it is set up.
<div class="warning"><b>WARNING:</b> SugarPhone requires SugarCube v2.36+ to function. Any earlier versions will not work. At the time of writing, the latest version of the Twine app comes with the required version.</div>
<div class="note"><b>NOTE:</b> While using Test/Debug mode will not make SugarPhone unusable, be aware that it may mess with its appearance even with debug views disabled. Whenever troubleshooting visual issues, ensure you are not in Test/Debug mode.</div>
Any links besides the navigation links below will open pages in a new tab.
All files come from the single SugarPhone download (<nowiki>SugarPhone.zip</nowiki>) at <a href="https://lc3.itch.io/sugarphone" target="_blank">lc3.itch.io/sugarphone</a>.
<b>Folder Structure</b>
<pre><nowiki>SugarPhone/
LICENSE.txt
README.txt
sugarphone_demo_docs.html <- The file you're looking at right now
sugarphone_template.html <- Fresh start project
demo_code_examples.tw <- The code for all chats found in the demo
images/ <- Images used in the demo
src/
css/
sugarphone.css
js/
sugarphone.min.js
sugarphone.js
tw/
storyinit.tw
widgets.tw
interface.tw</nowiki></pre>
<hr>
<h3>Index</h3>
<ul class="compact-list">
<li><a href="#install-from-template">Install from Template</a></li>
<li><a href="#install-from-code">Install to Existing Project</a></li>
</ul>
<hr>
<h2 id="install-from-template">Install from Template</h2>
Ensure you have the template file (''sugarphone_template.html'') and then refer to <a href="https://twinery.org/reference/en/story-library/creating.html#importing-stories" target="_blank">the official Twine import guide</a>.
<hr>
<h2 id="install-from-code">Install to Existing Project</h2>
SugarPhone is made up of ''THREE'' parts, all of which are required. The parts are CSS, JavaScript (JS), and TwineScript (aka regular SugarCube code). They are located in the <nowiki>css</nowiki>, <nowiki>js</nowiki>, and <nowiki>tw</nowiki> folders respectively.
<h3>1. CSS</h3>
<div class="note"><b>NOTE:</b> If you wish to keep SugarPhone's CSS separate, use <a href="https://www.w3schools.com/cssref/pr_import_rule.asp" target="_blank"><nowiki>@import</nowiki></a> or <a href="https://www.motoslave.net/sugarcube/2/docs/#functions-function-importstyles" target="_blank"><nowiki>importStyles()</nowiki></a>.</div>
If using the Twine desktop/web app, copy and paste the contents of ''sugarphone.css'' into your Story Stylesheet (<a href="https://twinery.org/reference/en/editing-stories/js-and-css.html" target="_blank">Official Twine Reference</a>).
If using a compiler like Tweego, place the ''sugarphone.css'' file in your source folder.
If the phone looks wonky after installation of all parts, there may be CSS rules conflicting with SugarPhone. This can be avoided by increasing specificity of the potential conflicts by prefixing them with <nowiki>#story</nowiki>, <nowiki>#passages</nowiki>, or <nowiki>.passage</nowiki> since SugarPhone is outside of the passage structure. Also ensure you are not using Test/Debug Mode.
For the lowest chance of style conflicts, place the SugarPhone CSS after your regular CSS.
<h3>2. JavaScript</h3>
<div class="note"><b>NOTE:</b> If you wish to keep SugarPhone's JS separate, use <a href="https://www.motoslave.net/sugarcube/2/docs/#functions-function-importscripts" target="_blank"><nowiki>importScripts()</nowiki></a>.</div>
If using the Twine desktop/web app, copy and paste the contents of ''sugarphone.js'' ''OR'' ''sugarphone.min.js'' into your Story JavaScript passage (<a href="https://twinery.org/reference/en/editing-stories/js-and-css.html" target="_blank">Official Twine Reference</a>).
The two files are functionally identical, but the minified file (''sugarphone.min.js'') is suggested if you have no plans to inspect or modify the code.
If using a compiler like Tweego, place one of the .js files into your source folder.
<h3>3. TwineScript</h3>
The TwineScript components of SugarPhone have three different purposes A) Initialization B) Widgets C) Interface. As such, they each have different destinations.
It is essential that the code is put into correctly named and/or tagged passages, as specified below and in the files.
<h4>A. StoryInit</h4>
Copy and paste the contents of ''storyinit.tw'' into your <nowiki>StoryInit</nowiki> passage. All of the phone's persistent data (settings, contacts, player name/icon) is stored in the <nowiki>$phone</nowiki> variable installed here.
<h4>B. Widgets</h4>
Copy and paste the contents of ''widgets.tw'' into any new passage tagged with <nowiki>widget</nowiki> and <nowiki>nobr</nowiki>. The phone will not function properly without these tags.
<h4>C. Phone Interface</h4>
Copy and paste the contents of ''interface.tw'' into a passage named ''SugarPhone'' and tagged <nowiki>nobr</nowiki>. The phone will not appear without this name.<h1>SugarPhone Key Terms</h1>
See the documentation sections for specific information on phone widgets and methods.
<<include "Key Terms Index">>
<<nobr>><h3 id="key-term-active-contact">
active contact
</h3><</nobr>>
A contact whose chat has been loaded by selecting their name from the phone's contact list.
<hr>
<<nobr>><h3 id="key-term-alert">
alert
</h3><</nobr>>
Alerts are small notifications that, in general, appear in three different situations. Alerts are set on a per-contact basis.
First, alerts appear in the phone's header. One alert appears for each contact with an alert active.
Second, an alert appears beside contacts with one active in the phone's contact list.
Lastly, a single alert will appear on <nowiki><<powerbutton>></nowiki> buttons when one or more alerts are active.
The default alert icon is <<=sp._getAlertIcon()>>. A custom alert icon can be set in the phone's settings, which will appear in all the above situations.
<div class="see"><b>SEE:</b> [[SugarPhone Settings]].</div>
<hr>
<<nobr>><h3 id="key-term-chat">
chat
</h3><</nobr>>
A passage containing a collection of texts to be displayed in SugarPhone. May also refer to: the phone's chat interface. e.g. "The active contact's chat is visible in the phone's chat (interface)."
<div class="see"><b>SEE:</b> <a href="#key-term-chat-passage-name-format">chat passage name (format)</a>, <a href="#key-term-text">text</a>.</div>
<hr>
<<nobr>><h3 id="key-term-chat-history">
chat history
</h3><</nobr>>
A list of unique chatKeys associated a contact.
All chats added via the <nowiki><<receivechat>></nowiki>, <nowiki><<sendchat>></nowiki>, and <nowiki><<textchoice>></nowiki>/<nowiki><<tchoice>></nowiki> widgets are part of the chat history. <nowiki><<include>></nowiki> can be used in chats, but only chats added via those widgets are a referable part of the history.
Contextually, chat history may also refer to the visible texts a player can see.
<hr>
<<nobr>><h3 id="key-term-chat-key">
chatKey
</h3><</nobr>>
The unique suffix for a specific chat with a contact. It needs to be unique on a per-contact basis.
<div class="see"><b>SEE:</b> <a href="#key-term-chat-passage-name-format">chat passage name (format)</a>, <a href="#key-term-contact-key">contactKey</a>.</div>
<hr>
<<nobr>><h3 id="key-term-chat-passage-name-format">
chat passage name (format)
</h3><</nobr>>
All chats added to the chat history must follow chat passage format for them to be accessed by SugarPhone.
Format: <nowiki>contactKey + $phone.config.chatNamInfix + chatKey</nowiki> (e.g. "Dad Chat First Contact").
May also be referred to occasionally as a ''chat title'' or ''chat passage title''.
<div class="see"><b>SEE:</b> <a href="#key-term-chat-key">chatKey</a>, <a href="#key-term-contact-key">contactKey</a>, <nowiki>$phone.config.chatNamInfix</nowiki> in [[SugarPhone Settings]].</div>
<hr>
<<nobr>><h3 id="key-term-choice-index">
choice index
</h3><</nobr>>
A choice index is defined for all <nowiki><<textchoice>></nowiki> and <nowiki><<tchoice>></nowiki> links, starting from 0 and incrementing for each link within the same chat.
When a choice link is clicked, its index is associated with the chat where it was clicked.
If <nowiki>$phone.config.disableChoiceHistory = true</nowiki> (default: <nowiki>false</nowiki>), choice indices are not recorded.
<div class="see"><b>SEE:</b> <nowiki>$phone.config.disableChoiceHistory</nowiki> in [[SugarPhone Settings]].</div>
<hr>
<<nobr>><h3 id="key-term-contact">
contact
</h3><</nobr>>
A contact, in general, is a textable character added via <nowiki><<addcontact>></nowiki> or <nowiki><<addcontactgroup>></nowiki>.
In some circumstances, a contact may be used for different purposes, such as displaying an image gallery or a reminder list. Regardless, they are defined and treated the same way by the phone.
<div class="see"><b>SEE:</b> <a href="#key-term-contact-key">contactKey</a>.</div>
<hr>
<<nobr>><h3 id="key-term-contact-key">
contactKey
</h3><</nobr>>
The unique name used to define a contact with the <nowiki><<addcontact>></nowiki> or <nowiki><<addcontactgroup>></nowiki> widget. It is the prefix of all chat passage names with that contact.
<div class="see"><b>SEE:</b> <a href="#key-term-chat-key">chatKey</a>, <a href="#key-term-chat-passage-name-format">chat passage name (format)</a>, <a href="#key-term-contact">contact</a>.</div>
<hr>
<<nobr>><h3 id="key-term-group-chat">
group chat
</h3><</nobr>>
A group chat is one in which the player receives messages from more than one identified person. This can be done in two ways.
Regular group chats are those defined via <nowiki><<addcontactgroup>></nowiki>. They require all <nowiki><<receive>></nowiki> widgets to receive a valid <nowiki>contactKey</nowiki>.
Group chats can also be ''simulated'' by passing all <nowiki><<receive>></nowiki> widget's in a regular contact's chat (defined via <nowiki><<addcontact>></nowiki>) display names as if they were separate contacts. This is only superficial, however, and does not support individual icons.
<div class="see"><b>SEE:</b> [[Group Chats]].</div>
<hr>
<<nobr>><h3 id="key-term-live-chat">
live chat
</h3><</nobr>>
A chat that can be interacted with via text advance links and choices.
Live chats are started with the <nowiki><<receivechat>></nowiki> and <nowiki><<sendchat>></nowiki> widgets.
<hr>
<<nobr>><h3 id="key-term-text">
text
</h3><</nobr>>
A single chat element between either <nowiki><<send>></nowiki> or <nowiki><<receive>></nowiki> widget tags.
May also be referred to as a ''message''.<<nobr>><h3>Key Terms Index</h3><</nobr>>
<ul class="compact-list">
<li><a href="#key-term-active-contact">active contact</a></li>
<li><a href="#key-term-alert">alert</a></li>
<li><a href="#key-term-chat-history">chat history</a></li>
<li><a href="#key-term-chat-key">chatKey</a></li>
<li><a href="#key-term-chat-passage-name-format">chat passage name (format)</a></li>
<li><a href="#key-term-choice-index">choice index</a></li>
<li><a href="#key-term-contact">contact</a></li>
<li><a href="#key-term-contact-key">contactKey</a></li>
<li><a href="#key-term-group-chat">group chat</a></li>
<li><a href="#key-term-live-chat">live chat</a></li>
<li><a href="#key-term-text">text</a></li>
</ul>
<hr><h1>Quick Start Code Samples</h1>
This quick start is intended as a code reference for common uses. The index is ordered more like the demo, rather than alphabetically, so foundational topics are at the top and supplementary topics are at the bottom.
For more information, please refer to the documentation ([[widgets|Phone Widget Documentation]], [[SugarPhone API]]), or the topic guides from the sidebar. If you're completely lost, go through the [[first time demo|Demo Start]].
<div class="see"><b>SEE:</b> [[Key Terms]]. The key terms may be helpful if you have not used any other sections of the documentation yet.</div>
<<include "Quick Start Index">>
<h3 id="define-contact">Defining a Contact</h3>
Contacts can be added via <nowiki><<addcontact>></nowiki> whenever needed. Trying to reference an undefined contact will cause errors in most widgets, so ensure contacts are defined as soon as they may be needed.
Trying to redefine a <nowiki>contactKey</nowiki> is ignored unless you use the <nowiki><<removecontact>></nowiki> widget first.
<b>Contact with the <nowiki>contactKey</nowiki> and name "Dad"</b>
<pre><nowiki><<addcontact "Dad">></nowiki></pre>
<b>Contact with the <nowiki>contactKey</nowiki> "dad" and name "Daddio"</b>
<pre><nowiki><<addcontact "dad" "Daddio, the vengeful">></nowiki></pre>
<b>Contact with the <nowiki>contactKey</nowiki> "dad", the name "Dad", and an icon</b>
<pre><nowiki><<addcontact "dad" "Dad" "images/dad_icon.png">></nowiki></pre>
<hr>
<h3 id="define-contact-group">Defining a Contact Group</h3>
Contact groups are defined identically to regular contacts, except that you must use the <nowiki><<addcontactgroup>></nowiki> widget.
Chats must use a valid <nowiki>contactKey</nowiki> with all <nowiki><<receive>></nowiki> widgets so that the appropriate contact's name or icon can display.
<b>Contact with the <nowiki>contactKey</nowiki> and name "fam"</b>
<pre><nowiki><<addcontactgroup "Family">></nowiki></pre>
<b>Contact with the <nowiki>contactKey</nowiki> "fam" and name "Family Chat"</b>
<pre><nowiki><<addcontactgroup "fam" "Family Chat">></nowiki></pre>
<b>Contact with the <nowiki>contactKey</nowiki> "fam", the name "Family Chat", and an icon</b>
<pre><nowiki>// Note: group chat icons only appear in popup alerts (disabled by default)
<<addcontactgroup "fam" "Family Chat" "images/family_icon.png">></nowiki></pre>
<hr>
<h3 id="setting-player-name">Setting the Player's Name/Icon</h3>
The player's name and icon are defined in the phone initialization code. They can be changed there or with the <nowiki><<set>></nowiki> macro at any time.
The player's name comes from <nowiki>$phone.config.playerName</nowiki> and the player's icon comes from <nowiki>$phone.config.playerIcon</nowiki>. They are blank by default and can be left that way, unless you wish either or both to appear in chats.
<div class="see"><b>SEE:</b> [[SugarPhone Settings]].</div>
<pre><nowiki><<set $phone.config.playerName = $yourPlayersName>>
<<set $phone.config.playerIcon = "images/your_players_icon.png">></nowiki></pre>
<hr>
<h3 id="update-contact">Updating a Contact</h3>
Contacts can be updated via <nowiki><<updatecontact>></nowiki> whenever needed. This includes contacts created via <nowiki><<addcontactgroup>></nowiki>.
<b>Updating contact with the <nowiki>contactKey</nowiki> "dad" to have the name "Daddio, the vengeful"</b>
<pre><nowiki><<updatecontact "dad" "name" "Daddio, the vengeful">></nowiki></pre>
<b>Updating contact with the <nowiki>contactKey</nowiki> "dad" to have an icon</b>
<pre><nowiki><<updatecontact "dad" "icon" "images/dad_icon_alt.png">></nowiki></pre>
<b>Updating contact with the <nowiki>contactKey</nowiki> "dad" to not display in the phone's contact list</b>
<pre><nowiki><<updatecontact "dad" "display" false>></nowiki></pre>
<hr>
<h3 id="add-inactive-chat">Adding Inactive Chats</h3>
Inactive chats will become a part of a contact's chat history with no opportunity for interaction. They are added with <nowiki><<receivechat>></nowiki> or <nowiki><<sendchat>></nowiki>.
<pre><nowiki>// These widgets behave the same when no third argument is given
<<receivechat "dad" "First Contact">>
<<sendchat "dad" "First Contact">></nowiki></pre>
<hr>
<h3 id="add-live-chat">Adding Live Chats</h3>
Live chats can be interacted with one text at a time until one of the following three conditions has been met: 1) all texts have been seen, 2) a new chat supersedes a contact's previous live chat, 3) <nowiki><<ignoreallchats>></nowiki> or <nowiki><<ignorechat>></nowiki> has been invoked.
Live chats are added with either of two widgets. The first, <nowiki><<receivechat>></nowiki>, should be used for contact-initiated conversations. It will set also set an alert. The second, <nowiki><<sendchat>></nowiki>, should be use for player-initiated conversations. It will also open the phone instead of setting an alert.
<div class="note"><b>NOTE:</b> Because <nowiki><<sendchat>></nowiki> opens the phone when adding a live chat, it's suggested to enclose it in an interactive macro, such as <nowiki><<link>></nowiki>.</div>
<b>Receive a live chat and set an alert</b>
<pre><nowiki><<receivechat "dad" "First Contact" true>></nowiki></pre>
<b>Send a live chat and open the phone when clicked</b>
<pre><nowiki><<link "Talk to Dad">><<sendchat "dad" "First Contact" true>><</link>></nowiki></pre>
<hr>
<h3 id="write-chats">Writing Chats</h3>
All chat messages must use the <nowiki><<send>></nowiki> and <nowiki><<receive>></nowiki> widgets. The player's name is attached to messages in the former widget and the contact's name is attached to the messages in the latter widget by default.
<div class="see"><b>SEE:</b> <a href="#quick-separating-chats">Separating Chats</a> for info on the <nowiki><hr></nowiki> elements present throughout the examples below.</div>
<h4>Regular Chats</h4>
<b>Simple chat</b>
<pre><nowiki><hr>
<<receive>>Hey, how are you doing?<</receive>>
<<send>>I'm doing well, thanks.<</send>></nowiki></pre>
<b>Specify a one-off name change</b>
<pre><nowiki><hr>
<<receive "sdgsdfhfg">>Something's wrong with my name<</receive>>
<<send>>Yeah, it looks like a key smash<</send>>
<<receive>>It's normal now<</receive>></nowiki></pre>
<h4>Group Chats</h4>
This assumes <nowiki><<addcontactgroup>></nowiki> was used. A valid <nowiki>contactKey</nowiki> must be passed to ''every'' <nowiki><<receive>></nowiki> widget. <nowiki><<send>></nowiki> can be used as normal.
<b>Simple Use</b>
<pre><nowiki><hr>
<<receive "nyla">>I'll have nyla's name displayed<</receive>>
<<receive "larry">>and i'll have larry's<</receive>>
<<receive "nyla" "Nylahhhh">>You can still override the display name on a per-message basis<</receive>>
<<send>>Sent messages are the same<</send>></nowiki></pre>
<b>Alternative use with temporary variables for <nowiki>contactKeys</nowiki></b>
<pre><nowiki>// Setting the temp vars in the first chat allows all that follow to use them
<<set _n = "nyla">><<set _l = "larry">>
<hr>
<<receive _n>>I'll have nyla's name displayed<</receive>>
<<receive _l>>and i'll have larry's<</receive>>
<<receive _n "Nylahhhh">>You can still override the display name on a per-message basis<</receive>>
<<send>>Sent messages are the same<</send>></nowiki></pre>
<hr>
<h3 id="branch-chats">Branching Chats</h3>
<nowiki><<tchoice>></nowiki> and <nowiki><<textchoice>></nowiki> behave the exact same, except <nowiki><<textchoice>></nowiki> can execute code. Similar to <nowiki><<links>></nowiki>, the first argument is the <nowiki>linkText</nowiki> and the second argument is a <nowiki>chatKey</nowiki> rather than a passage name. Both arguments are required.
<div class="note"><b>NOTE:</b> Choices will only become visible after every message in a live chat is visible. That means even if a choice widget is the first thing in a chat, it will not appear until the messages that come after have been revealed.</div>
<pre><nowiki><<receive>>Hey, how are you doing?<<receive>>
<<send>>I'm doing well, thanks.<</send>>
<<textchoice "This text choice can execute code" "First Contact">><<set $dadAffection +=1>><</textchoice>>
<<tchoice "This one cant" "First Contact">></nowiki></pre>
<hr>
<h3 id="end-chats">Ending Chats</h3>
Chats are automatically flagged as finished when the last text is visible, but a <nowiki><<textfinish>></nowiki>/<nowiki><<tfinish>></nowiki> link can allow users to explicitly end the conversation and close the phone.
If the chat is closed before the link is clicked, it will not appear again.
<div class="note"><b>NOTE:</b> Like choices, finishing links will only become visible after every message in a live chat is visible. That means even if a finish widget is the first thing in a chat, it will not appear until the messages that come after have been revealed.</div>
<b>End chat and set a variable</b>
<pre><nowiki><<receive>>Hey, how are you doing?<</receive>>
<<send>>I'm doing well, thanks.<</send>>
<<textfinish>><<set $foo = "bar">><</textfinish>> → Link with the text "Close"</nowiki></pre>
<b>End chat without setting variables via <nowiki><<tfinish>></nowiki></b>
<pre><nowiki><<receive>>Hey, how are you doing?<</receive>>
<<send>>I'm doing well, thanks.<</send>>
<<tfinish>> → Link with the text "Close"</nowiki></pre>
<b>Change the link text</b>
<pre><nowiki><<textfinish "Go sleep">><</textfinish>>
<<tfinish "Go sleep">></nowiki></pre>
<hr>
<h3 id="remember-choices">Remembering Choices</h3>
All three options assume the chat "dad Chat First Contact" and "dad Chat First Contact Question" exist. If things are happening out of order by accident, all the below methods will return <nowiki>null</nowiki> (in the case of <nowiki>sp.choiceMadeIn()</nowiki>) or <nowiki>false</nowiki> (in the case of the other two).
<<include "Choice Index Warning">>
<div class="note"><b>NOTE:</b> When <nowiki>$phone.config.disableChoiceHistory = true</nowiki> (default: <nowiki>false</nowiki>), choice selections are not remembered. This means <nowiki>sp.choiceMadeIn()</nowiki> and <nowiki>sp.madeChoice()</nowiki> will always return <nowiki>null</nowiki> or <nowiki>false</nowiki> respectively, but <nowiki>sp.hadChat()</nowiki> will continue to function normally.</div>
<div class="see"><b>SEE: [[Topic: Checking Choices|Checking Choices]].</b></div>
<h4>Option 1: <nowiki>sp.choiceMadeIn()</nowiki></h4>
<b>Previous choice with the active contact</b>
<pre><nowiki><<send>>Hey, how are you?<</send>>
// All white space and line breaks are ignored.
<<receive>>
<<if sp.choiceMadeIn("First Contact") === 0>>
You already asked me that
<<else>>
I'm doing well, thanks.
<</if>>
<</receive>></nowiki></pre>
<b>Previous choice outside of the phone or with a different contact</b>
<pre><nowiki>"What choice did you make with dad?" they ask.
<<if sp.choiceMadeIn("First Contact", "dad") === 0>>
"The first choice," you say.
<<else>>
"A different choice," you say
<</if>></nowiki></pre>
<h4>Option 2: <nowiki>sp.madeChoice()</nowiki></h4>
<b>Previous choice with the active contact</b>
<pre><nowiki><<send>>Hey, how are you?<</send>>
<<receive>>
<<if sp.madeChoice(0, "First Contact")>>
You already asked me that.
<<else>>
I'm doing well, thanks.
<</if>>
<</receive>></nowiki></pre>
<b>Previous choice outside of the phone or with a different contact</b>
<pre><nowiki>"What choice did you make with dad?" they ask.
<<if sp.madeChoice(0, "First Contact", "dad")>>
"The first choice," you say.
<<else>>
"A different choice," you say
<</if>></nowiki></pre>
<h4>Option 3: <nowiki>sp.hadChat()</nowiki></h4>
This method can tell you if any number of chats exist in the chat history. It does not differentiate if the chat was ignored or not.
<pre><nowiki><<send>>Hey, how are you?<</send>>
<<receive>>
<<if sp.hadChat("dad", "How Are You 1", "How Are You 2", "How Are You 3") > 2>>
You already asked me that THREE TIMES.
<<else>>
I'm doing well, thanks.
<</if>>
<</receive>></nowiki></pre>
<hr>
<h3 id="ignore-chats">Ignoring Chats</h3>
Ignoring chats is the process by which live chats become inactive without the player having seen their full contents/selecting their text choices.
<div class="note"><b>NOTE:</b> When <nowiki>$phone.config.disableIgnoredChatHistory = true</nowiki> (default: <nowiki>false</nowiki>), ignoring chats makes them inactive without keeping any record that they were ignored.</div>
<div class="see"><b>SEE:</b> [[Topic: Ignored Chats|Ignoring Chats]].</div>
Chats are ignored in two situations.
<h4>1. Automatically when a new chat is added</h4>
It does not make a difference if the chat being added is active or inactive--the previous live chat is still ignored.
<b>Live chat ignored when new inactive chat added</b>
<pre><nowiki><<receivechat "dad" "First Contact" true>>
<<sendchat "dad" "Check In">></nowiki></pre>
<b>Live chat ignored when new live chat added</b>
<pre><nowiki><<receivechat "dad" "First Contact" true>>
<<sendchat "dad" "Check In" true>></nowiki></pre>
<h4>2. Manually</h4>
There are two widgets for ignoring chats: <nowiki><<ignoreallchats>></nowiki> and <nowiki><<ignorechat>></nowiki>. Inactive chats cannot and will not be ignored through these.
<nowiki><<ignoreallchats>></nowiki> ignores all live chats.
<nowiki><<ignorechat>></nowiki> ignores the live chat of a specified contact.
<b>Records the most recent chat with "dad" as ignored IF the chat is live</b>
<pre><nowiki><<ignorechat "dad">></nowiki></pre>
<hr>
<h3 id="remember-ignored-chats">Remembering Ignored Chats</h3>
Ignoring a chat doesn't do anything bad. At worst, a live chat becomes inactive and its contents will be displayed for a player in full.
Remembering whether a chat was ignored is valuable when managing the texts that appear in a contact's chat history, otherwise chats may be littered with texts the player never had a chance to interact with or send.
<div class="note"><b>NOTE:</b> When <nowiki>$phone.config.disableIgnoredChatHistory = true</nowiki> (default: <nowiki>false</nowiki>), <nowiki>sp.chatIgnored()</nowiki> will always return <nowiki>null</nowiki>. It will also do so if the chat is not a part of the chat history, otherwise it will return <nowiki>true</nowiki> or <nowiki>false</nowiki>.</div>
<div class="see"><b>SEE:</b> [[Topic: Ignored Chats|Ignoring Chats]].</div>
<h4>Check the Current Chat:</h4>
This can be used to display alternate text in the event a player never has a chance to respond to a message. This can be unnecessary, however, in situations where no sent texts will be visible and the received messages don't feel odd without followup.
<pre><nowiki>// When no arguments are passed, sp.chatIgnored() infers the current chat and contact
<<receive>>Hey, I'd love to get your help with something<</receive>>
<<if sp.chatIgnored()>>
<<receive>>Never mind, I figured it out.<</receive>>
<</if>>
// Text choices do not need to be wrapped by the <<if>>
// They can only be visible when a chat is live
<<tchoice "Sure, I'd love to help!" "Help">></nowiki></pre>
<h4>Check a Previous Chat:</h4>
<pre><nowiki>// When one argument is passed, sp.chatIgnored() infers the active contact
<<receive>>Hey, I'd love to get your help with something<<if sp.chatIgnored("Help") is false>> again<</if>>?<</receive>>
<<tchoice "Sure, I'd love to help!" "Help Again">></nowiki></pre>
<h4>Check a Specific Chat and Contact:</h4>
<pre><nowiki><<receive>>Hey, can you help me with something<<if sp.chatIgnored("Help" "mom") is false>> like you did with mom<</if>>?<</receive>>
<<tchoice "Sure, I'd love to help!" "Help Again">></nowiki></pre>
<hr>
<h3 id="line-breaks">Adding Line Breaks to Chats</h3>
All chats and phone functionality ignore line breaks by default. <nowiki><br></nowiki> elements can be manually added to change formatting of texts.
<b>No line break displays in sent message</b>
<pre><nowiki><<receive>>Hey, how are you doing?<</receive>>
<<send>>I'm doing well.
Thanks.<</send>></nowiki></pre>
<b>Line break displays in sent message</b>
<pre><nowiki><<receive>>Hey, how are you doing?<</receive>>
<<send>>I'm doing well.<br>Thanks.<</send>></nowiki></pre>
<hr>
<h3 id="quick-separating-chats">Separating Chats</h3>
The phone does nothing to differentiate one chat from another once they have been loaded. If you would like to differentiate chats visually to players, the easiest way is with a <a href="https://www.w3schools.com/tags/tag_hr.asp" target="_blank"><nowiki><hr></nowiki></a> element (link opens in a new tab).
Open the phone to see several of these elements in the pre-loaded sample chats.
<div class="note"><b>NOTE:</b> Only place <nowiki><hr></nowiki> elements at the beginning of chats that may be live. The element is not taken into account by the phone's live chat code, and so it will be visible from the get-go and any messages prior to it will pop into existence above the line. Chats that will never be live can have <nowiki><hr></nowiki> elements placed anywhere.</div>
<pre><nowiki><hr>
<<send>>The horizontal line element above makes it clear this is a new conversation<</send>></nowiki></pre>
<hr>
<h3 id="lock-unlock">Lock/Unlock Phone</h3>
<div class="note"><b>NOTE:</b> Undocked phones have no UI when closed, so hiding undocked phones is unnecessary.</div>
<b>Disable opening the phone and close it if it's currently open</b>
<pre><nowiki><<lockphone>></nowiki></pre>
<b>Disable opening the phone and hide the phone's UI</b>
<pre><nowiki><<lockphone true>></nowiki></pre>
<b>Return phone to its regular closed unlock state</b>
<pre><nowiki><<unlockphone>></nowiki></pre>
<hr>
<h3 id="open-close">Open/Close the Phone</h3>
<h4>Robust Toggle Buttons/Links</h4>
SugarPhone has two built in widgets, <nowiki><<powerbutton>></nowiki> and <nowiki><<powerlink>></nowiki>, that create a button and link respectively for toggling the phone open and closed. They are self-updating and reflect the phone's lock state. <nowiki><<powerbutton>></nowiki> also display an alert if any are active and/or animates if any live linkchats are pending.
<b>Bare link with a power or lock icon and the text "Toggle Phone"</b>
<pre><nowiki><<powerlink "Toggle Phone">></nowiki></pre>
<b>Button with a power or lock icon and the text "Toggle Phone"</b>
<pre><nowiki><<powerbutton "Toggle Phone">> // Also displays an alert if any are pending</nowiki></pre>
<b>Same as previous, but the button will animate when a chat is live</b>
<pre><nowiki><<powerbutton "Toggle Phone" true>></nowiki></pre>
<h4>Plain Buttons/Links</h4>
The toggle, open, and close phone widgets can be used with <nowiki><<buttons>></nowiki>, <nowiki><<links>></nowiki>, or on their own. The phone will not open when it is locked, even when <nowiki><<openphone>></nowiki> is used.
<b>Link that will open or close the phone, depending on its current state</b>
<pre><nowiki><<link "Toggle Phone">>
<<togglephone>>
<</link>></nowiki></pre>
<b>Link that only opens the phone</b>
<pre><nowiki><<link "Open Phone">>
<<openphone>>
<</link>></nowiki></pre>
<b>Link that only closes the phone</b>
<pre><nowiki><<link "Close Phone">>
<<closephone>>
<</link>></nowiki></pre><h3>Quick Start Index:</h3>
<ul class="compact-list">
<li><a href="#define-contact">Defining a Contact</a></li>
<li><a href="#define-contact-group">Defining a Contact Group</a></li>
<li><a href="#update-contact">Updating a Contact</a></li>
<li><a href="#setting-player-name">Setting the Player's Name/Icon</a></li>
<li><a href="#add-inactive-chat">Adding Inactive Chats</a></li>
<li><a href="#add-live-chat">Adding Live Chats</a></li>
<li><a href="#write-chats">Writing Chats</a></li>
<li><a href="#branch-chats">Branching Chats</a></li>
<li><a href="#end-chats">Ending Chats</a></li>
<li><a href="#remember-choices">Remembering Choices</a></li>
<li><a href="#ignore-chats">Ignoring Chats</a></li>
<li><a href="#remember-ignored-chats">Remembering Ignored Chats</a></li>
<li><a href="#line-breaks">Adding Line Breaks to Chats</a></li>
<li><a href="#quick-separating-chats">Separating Chats</a></li>
<li><a href="#lock-unlock">Lock/Unlock the Phone</a></li>
<li><a href="#open-close">Open/Close the Phone</a></li>
</ul>
<hr><h1>SugarPhone Settings</h1>
<nowiki>$phone.config</nowiki> has a number of settings that affect how the SugarPhone system will use and interpret instructions.
The settings can be changed directly on the <nowiki>$phone</nowiki> object added during [[installation|Installation]], elsewhere in the <nowiki>StoryInit</nowiki> passage, or on the fly at runtime.
<div class="note"><b>NOTE:</b> Several of the phones settings can be implemented as toggles that players may use, such as chat icons. These settings are noted, though you will need to implement your own way for players to change them. All settings affecting chats are updated the next time a chat is loaded. Many of these settings can be toggled in the sidebar right now!</div>
<<include "SugarPhone Settings Index">>
<<nobr>><h2 id="config-alert-icon">
<nowiki>$phone.config.alertIcon</nowiki> ↔ <i>imgURL</i> (default: <nowiki>""</nowiki>)
</h2><</nobr>>
What icon should display for alerts in the phone's header, beside <nowiki><<powerbutton>></nowiki> buttons, and in phone contact links.
When empty (default), a <span class='sc-icon sc-exclamation' style='color: red;'></span> will display for alerts.
When defined, this image can be styled with the selector <nowiki>.custom-alert-icon img</nowiki>. Be aware of where this icon appears (stated above) when making changes.
<div class="note"><b>NOTE:</b> SugarPhone does not validate this url. If regular alerts display but a custom icon does not, ensure the filepath is correct.</div>
<h3>Examples:</h3>
<pre><nowiki><<set $phone.config.alertIcon = "images/alert.png">></nowiki></pre>
<hr>
<<nobr>><h2 id="config-allow-chat-icon-repeat">
<nowiki>$phone.config.allowChatIconRepeat</nowiki> ↔ <i>boolean</i> (default: <nowiki>false</nowiki>)
</h2><</nobr>>
This setting can be toggled by players, if desired.
Determines whether successive messages by the same contact (or player) should omit their icon.
<div class="note"><b>NOTE:</b> Icons do not display unless <nowiki>$phone.config.displayChatIcons = true</nowiki> (default: <nowiki>false</nowiki>).</div>
<div class="see"><b>SEE:</b> <a href="#config-display-chat-icons"><nowiki>$phone.config.displayChatIcons</nowiki></a>.</div>
<h3>Examples:</h3>
<pre><nowiki><<set $phone.allowChatIconRepeat = true>></nowiki></pre>
<hr>
<<nobr>><h2 id="config-allow-chat-name-repeat">
<nowiki>$phone.config.allowChatNameRepeat</nowiki> ↔ <i>boolean</i> (default: <nowiki>false</nowiki>)
</h2><</nobr>>
This setting can be toggled by players, if desired.
Determines whether successive messages by the same contact (or player) should omit their name.
<div class="see"><b>SEE:</b> <a href="#config-display-chat-names"><nowiki>$phone.config.displayChatNames</nowiki></a>.</div>
<h3>Examples:</h3>
<pre><nowiki><<set $phone.allowChatNameRepeat = true>></nowiki></pre>
<hr>
<<nobr>><h2 id="config-load-delay">
<nowiki>$phone.config.chatLoadDelay</nowiki> ↔ <i>integer</i> (default: <nowiki>500</nowiki>)
</h2><</nobr>>
How long the chat loading animation should last in milliseconds. For example, 500 milliseconds is 0.5 seconds.
If 0, the animation will not play. This may mean players see the chat jump around as elements load, so a delay is suggested, especially when icons are present.
<div class="see"><b>SEE:</b> [[Simple CSS]] for info on defining a loading gif.</div>
<h3>Examples:</h3>
<pre><nowiki><<set $phone.config.chatLoadDelay = 750>></nowiki></pre>
<hr>
<<nobr>><h2 id="config-chat-name-infix">
<nowiki>$phone.config.chatNameInfix</nowiki> ↔ <i>string</i> (default: <nowiki>" Chat "</nowiki>)
</h2><</nobr>>
The string separating a <nowiki>contactKey</nowiki> and <nowiki>chatKey</nowiki> in all chat passage names.
Changing this during game play will break the phone.
<h3>Examples:</h3>
<pre><nowiki>→ Assuming $phone.config.chatNameInfix is " Chat "
sp.getChatName("Dad", "Example") → outputs "Dad Chat Example"
→ Assuming $phone.config.chatNameInfix is " "
sp.getChatName("Dad", "Example") → outputs "Dad Example"
→ Assuming $phone.config.chatNameInfix is ""
sp.getChatName("Dad", "Example") → outputs "DadExample"</nowiki></pre>
<hr>
<<nobr>><h2 id="config-chat-scroll-speed">
<nowiki>$phone.config.chatScrollSpeed</nowiki> ↔ <i>integer</i> (default: <nowiki>600</nowiki>)
</h2><</nobr>>
How long the chat should scroll for when advancing text in milliseconds. For example, 600 milliseconds is 0.6 seconds.
Players are also unable to interact with advance or choice links during this time. This helps prevent both the chat from scrolling too abruptly and so that players don't accidentally spam click through important decisions. As such, setting this value too low is not suggested.
<div class="note"><b>NOTE:</b> Setting this to a low value may be helpful in testing if all you wish to do is complete chats quickly and confirm their flow.</div>
<h3>Examples:</h3>
<pre><nowiki><<set $phone.config.chatScrollSpeed = 400>></nowiki></pre>
<hr>
<<nobr>><h2 id="config-disable-choice-history">
<nowiki>$phone.config.disableChoiceHistory</nowiki> ↔ <i>boolean</i> (default: <nowiki>false</nowiki>)
</h2><</nobr>>
Determines whether choices made in chats should be recorded.
When <nowiki>true</nowiki>, the following methods will always return <nowiki>false</nowiki> or <nowiki>null</nowiki>: <nowiki>sp.choiceMadeIn(), sp.madeChoice()</nowiki>.
<h3>Examples:</h3>
<pre><nowiki>→ Assuming $phone.config.disableChoiceHistory = true
:: jay Chat Hello
<<receive>>Hellloooooo!<</receive>>
<<tchoice "Hey" "Followup">>
:: jay Chat Followup
// choiceMadeIn() will return 'null'
<<send>>Hey, I just chose the choice <<print sp.choiceMadeIn("Hello")>><</send>></nowiki></pre>
<hr>
<<nobr>><h2 id="config-disable-ignored-chat-history">
<nowiki>$phone.config.disableIgnoredChatHistory</nowiki> ↔ <i>boolean</i> (default: <nowiki>false</nowiki>)
</h2><</nobr>>
Determines whether ignored chats should be recorded.
<h3>Examples:</h3>
<pre><nowiki>→ Assuming $phone.config.disableIgnoredChatHistory
<<receivechat "char" "Hello" true>> → Receive a new live chat
<<ignorechat "char">> → End alert and make chat inactive
<<print sp.chatIgnored("char", "Hello")>> → prints 'null'</nowiki></pre>
<hr>
<<nobr>><h2 id="config-display-chat-icons">
<nowiki>$phone.config.displayChatIcons</nowiki> ↔ <i>boolean</i> (default: <nowiki>false</nowiki>)
</h2><</nobr>>
This setting can be toggled by players, if desired.
Determines whether contact icons should be displayed alongside messages in chats.
This setting can be enabled even when name display is disabled.
<div class="note"><b>NOTE:</b> Icons are entirely optional even when enabled, so you may define icons for as few or as many contacts as you wish. Contacts without icons defined will display as they would with icons disabled entirely.</div>
<div class="see"><b>SEE:</b> <a href="#config-allow-chat-icon-repeat"><nowiki>$phone.config.allowChatIconRepeat</nowiki></a>.</div>
<h3>Examples:</h3>
<pre><nowiki><<set $phone.config.displayChatIcons = true>></nowiki></pre>
<hr>
<<nobr>><h2 id="config-display-chat-names">
<nowiki>$phone.config.displayChatNames</nowiki> ↔ <i>boolean</i> (default: <nowiki>true</nowiki>)
</h2><</nobr>>
This setting can be toggled by players, if desired.
Determines whether contact names should be displayed with messages in chats.
<div class="see"><b>SEE:</b> <a href="#config-allow-chat-name-repeat"><nowiki>$phone.config.allowChatNameRepeat</nowiki></a>.</div>
<h3>Examples:</h3>
<pre><nowiki><<set $phone.config.displayChatNames = false>></nowiki></pre>
<hr>
<<nobr>><h2 id="config-docked">
<nowiki>$phone.config.docked</nowiki> ↔ <i>boolean</i> (default: <nowiki>true</nowiki>)
</h2><</nobr>>
This setting can be toggled by players, if desired. A passage reload or transition is required for it to take effect.
Determines whether the phone UI rests at the bottom of the screen or is invisible until opened.
<div class="see"><b>SEE:</b> When using an un-docked phone, the <nowiki><<powerbutton>></nowiki> or <nowiki><<powerlink>></nowiki> widgets are highly suggested for toggling the phone. [[Widget documentation|Phone Widget Documentation]] for more information.</div>
<h3>Examples:</h3>
<pre><nowiki><<set $phone.config.docked = false>></nowiki></pre>
<hr>
<<nobr>><h2 id="config-max-loaded-chats">
<nowiki>$phone.config.maxLoadedChats</nowiki> ↔ <i>integer</i> (default: 25)
</h2><</nobr>>
How many of the most recent chats should be loaded for players. At least one chat will always be displayed, even if set to 0.
Chats outside of this number and their associated information (i.e. choices, ignore state) are still recorded and will be visible again if <nowiki>maxLoadedChats</nowiki> is raised during game play.
Chats are not pruned until the chat is reloaded, so branching conversations will not cause old chats to become invisible immediately--e.g. A branching live conversation when <nowiki>maxLoadedChats=1</nowiki> will still show chats prior to each branch until the chat is closed and reopened.
<div class="note"><b>NOTE:</b> Only ''explicitly named'' chats are counted against this number. That is to say, chats added to the chat history by <nowiki><<sendchat>></nowiki>, <nowiki><<receivechat>></nowiki>, or <nowiki><<textchoice>></nowiki>/<nowiki><<tchoice>></nowiki>. Passages present through <nowiki><<include>></nowiki> are untracked and are considered a part of the chat that includes them.</div>
<h3>Examples:</h3>
<pre><nowiki><<set $phone.config.maxLoadedChats = 1>></nowiki></pre>
<hr>
<<nobr>><h2 id="config-player-icon">
<nowiki>$phone.config.playerIcon</nowiki> ↔ <i>imgURL</i> (default: <nowiki>""</nowiki>)
</h2><</nobr>>
What icon should display with <nowiki><<send>></nowiki> widget messages. Icon display must also be enabled (default: <nowiki>false</nowiki>).
<div class="note"><b>NOTE:</b> SugarPhone does not validate this url. If icons are enabled but your icon does not display, ensure the filepath is correct.</div>
<div class="see"><b>SEE:</b> <a href="#config-display-chat-icons"><nowiki>$phone.config.displayChatIcons</nowiki></a>.</div>
<h3>Examples:</h3>
<pre><nowiki><<set $phone.config.playerIcon = "images/icons/player.png">></nowiki></pre>
<hr>
<<nobr>><h2 id="config-player-name">
<nowiki>$phone.config.playerName</nowiki> ↔ <i>string</i> (default: <nowiki>""</nowiki>)
</h2><</nobr>>
What name should display with <nowiki><<send>></nowiki> widget messages. Name display must also be enabled (default: <nowiki>true</nowiki>).
<div class="note"><b>NOTE:</b> SugarPhone does not validate this url. If icons are enabled but your icon does not display, ensure the filepath is correct.</div>
<div class="see"><b>SEE:</b> <a href="#config-display-chat-names"><nowiki>$phone.config.displayChatNames</nowiki></a>.</div>
<h3>Examples:</h3>
<b>Set it to a string</b>
<pre><nowiki><<set $phone.config.playerName = "Player">></nowiki></pre>
<b>Set it to some player's input</b>
<pre><nowiki><<set $phone.config.playerName = $yourPlayersInput>></nowiki></pre>
<hr>
<<nobr>><h2 id="config-popup-alerts">
<nowiki>$phone.config.popupAlerts</nowiki> ↔ <i>boolean</i> (default: <nowiki>false</nowiki>)
</h2><</nobr>>
This setting can be toggled by players, if desired.
If <nowiki>true</nowiki>, popup alerts will appear ''once'' when an alert is first set.
Alerts are set by the <nowiki><<receivechat>></nowiki> widget when a chat is live OR when the <nowiki><<textalert>></nowiki> widget is used in any chat state.
Popups will appear in the bottom-right of the screen and persist for 5 seconds. When clicked, the phone is opened and the popup is removed.
Popups preview the first message enclosed by a <nowiki><<receive>></nowiki> widget in a contact's most recent chat. If the <nowiki><<receive>></nowiki> widget is not used in the most recent chat, a popup is not created.
<div class="note"><b>NOTE</b>: Popup alerts support individual contact names in group chats; the popup's header will contain the group name, and the contact's name is displayed before the preview text. HOWEVER, if you are making use of temporary variables for <nowiki><<receive>></nowiki> <nowiki>contactKey</nowiki> arguments, they cannot be evaluated in the text previews. Per-message names are also ignored and instead the name defined with the <nowiki>contactKey</nowiki> is used.</div>
<h3>Examples:</h3>
All examples assume <nowiki>$phone.config.popupAlerts = true</nowiki>.
<b>The chat is not live, no popup is created</b>
<pre><nowiki><<receivechat "Dad" "Pop Up Example">></nowiki></pre>
<b>The chat is live, a popup is created</b>
<pre><nowiki><<receivechat "Dad" "Pop Up Example" true>></nowiki></pre>
<b>The chat remains in its current state and a popup is created</b>
<pre><nowiki>// Best practice: Use in conjunction with inactive chats that should still trigger alerts
<<receivechat "Dad" "Pop Up Example">><<textalert "Dad">></nowiki></pre>
<hr>
<<nobr>><h2 id="config-press-p-to-toggle">
<nowiki>$phone.config.pressPToToggle</nowiki> ↔ <i>boolean</i> (default: <nowiki>false</nowiki>)
</h2><</nobr>>
When <nowiki>true</nowiki>, pressing "p" on the keyboard will toggle the phone open or closed if it's not locked.
<div class="warning"><b>WARNING:</b> The listener for this event is extremely general. If enabled, it WILL trigger when your players are doing text input. Locking the phone or temporarily disabling this setting will prevent this.</div>
<div class="note"><b>NOTE:</b> If you wish to set up your own phone events, try <a href="https://github.com/ChapelR/custom-macros-for-sugarcube-2/blob/master/docs/event-macros.md">Chapel's Event Macro</a>. This can be used in conjunction with the open, close, lock, unlock widgets, etc.</div>
<h3>Examples:</h3>
<pre><nowiki><<set $phone.config.pressPToToggle = true>></nowiki></pre><h3>Properties</h3>
<ul class="compact-list">
<li><a href="#config-alert-icon">Alert Icon</a></li>
<li><a href="#config-allow-chat-icon-repeat">Allow Chat Icon Repeat</a></li>
<li><a href="#config-allow-chat-name-repeat">Allow Chat Name Repeat</a></li>
<li><a href="#config-load-delay">Chat Load Delay</a></li>
<li><a href="#config-chat-name-infix">Chat Name Infix</a></li>
<li><a href="#config-chat-scroll-speed">Chat Scroll Speed</a></li>
<li><a href="#config-disable-choice-history">Disable Choice History</a></li>
<li><a href="#config-disable-ignored-chat-history">Disable Ignored Chat History</a></li>
<li><a href="#config-display-chat-icons">Display Chat Icons</a></li>
<li><a href="#config-display-chat-names">Display Chat Names</a></li>
<li><a href="#config-docked">Docked</a></li>
<li><a href="#config-max-loaded-chats">Max Loaded Chats</a></li>
<li><a href="#config-player-icon">Player Icon</a></li>
<li><a href="#config-player-name">Player Name</a></li>
<li><a href="#config-popup-alerts">Pop Up Alerts</a></li>
<li><a href="#config-press-p-to-toggle">Press "P" To Toggle</a></li>
</ul>
<hr><h1>Adding to the Phone Header</h1>
So long as the phone UI is visible, players are always able to see and interact with the header. This means it can be used as a secondary sidebar for quick links and brief information on the game's state. Information that takes up multiple lines should be placed elsewhere.
<h3>Index</h3>
<ul class="compact-list">
<li><a href="#phone-header-sections">Header Sections</a></li>
<li><a href="#updating-the-header">Updating the Header</a></li>
</ul>
<hr>
<h2 id="phone-header-sections">Header Sections</h2>
The phone's header is made up of <b>3</b> sections--the <b>left</b>, the <b>centre</b>, and the <b>right</b>. Only the latter two can be edited, and they are only updated after each passage transition by default.
<div class="see"><b>SEE:</b> <a href="#updating-the-header">Updating the Header</a>.</div>
<h3>The Left</h3>
This section holds the text alerts. It cannot be edited and is updated automatically anytime the <nowiki><<updatealerts>></nowiki> widget is called (see the [[Phone Widget Documentation]] for more info).
<div class="see"><b>SEE:</b> <nowiki>$phone.config.alertIcon</nowiki> in [[SugarPhone Settings]] to change the alert icon.</div>
<h3>The Centre</h3>
This optional section can be added with the <nowiki>SugarPhone Head Centre</nowiki> passage. Line breaks are ignored in this passage. If the passage does not exist, a <nowiki><<powerlink>></nowiki> is displayed here.
<div class="note"><b>NOTE:</b> Keeping a <nowiki><<powerlink>></nowiki> here (or some other phone toggle) is ''highly'' suggested. SugarPhone obscures the entire screen on small devices and keyboard shortcuts to toggle the phone will be inaccessible to most mobile users.</div>
<h4>Examples:</h4>
<pre><nowiki>:: SugarPhone Head Centre
/* A phone toggle link with a power icon */
<<powerlink>> |
/* A link that opens the Saves dialog */
<<link "Saves">><<run UI.saves()>><</link>> |
/* A link that opens the Restart dialog */
<<link "Restart">><<run UI.restart()>><</link>></nowiki></pre>
<h3>The Right</h3>
This optional section can be added with the <nowiki>SugarPhone Head Right</nowiki> passage. Line breaks are ignored in this passage.
This section will be right-justified in the phone's header and is useful for displaying things such as time, date, or other elements that users would expect.
<h4>Examples:</h4>
<b>Simple information on the current day and time</b>
<pre><nowiki>:: SugarPhone Head Centre
$weekday $time</nowiki></pre>
<hr>
<h2 id="updating-the-header">Updating the Header</h2>
As said above, the editable sections of the phone's header are only updated after each passage transition.
To update them more frequently, use the <nowiki><<updateheader>></nowiki> widget. When called, the editable sections will be reloaded if either <nowiki>SugarPhone Head Centre</nowiki> or <nowiki>SugarPhone Head Right</nowiki> passages exist.
<div class="see"><b>SEE:</b> [[Phone Widget Documentation]]</div>
<h4>Examples:</h4>
<pre><nowiki>→ Assuming one of the header sections displays $time
<<link "Pass the time [1h]">>
<<set $time += 1>>
<<updateheader>>
<</link>></nowiki></pre><h1>Checking Choices</h1>
<<include "Chat Variable Warning">>
Checking choices in SugarPhone is a straightforward process that can be done in several ways.
This section covers how SugarPhone records choices, plus the documentation on how to refer to those choices. All choices are checked through the phone's API ([[full documentation here|SugarPhone API]])
<dv class="note"><b>NOTE:</b> When <nowiki>$phone.config.disableChoiceHistory = true</nowiki> (default: <nowiki>false</nowiki>), choices are NOT recorded. In this case, the chat history can only be checked through <nowiki>sp.hadChat()</nowiki>.</dv>
<h3>Index</h3>
<a href="#checking-choices-recorded">How Are Choices Recorded?</a>
<a href="#checking-choices-access">How to Access Choices?</a>
<a href="#checking-choices-summary">Summary</a>
<hr>
<h2 id="checking-choices-recorded">How Are Choices Recorded?</h2>
All text choices generate an index (a number in an ordered list, starting from 0) for each link. This choice index is relative to the others in the same chat.
We can see what that looks like in action if you click the link below. Clicking it again will reset the demo.
<<link "Try Me">><<removechat "Dad" "Choices">><<removechat "Dad" "Choices Followup">><<receivechat "Dad" "Choices" true>><</link>>
When you're done, we can look at the code of the first chat and its choices.
<pre><nowiki>:: Dad Chat Choices
<<receive>>Hey, which choice are you going to make?<</receive>>
<<textchoice "I'm picking the first, its choice index is 0" "Choices Followup">><</textchoice>>
<<tchoice "I'm picking the second, its choice index is 1" "Choices Followup">>
<<tchoice "I'm picking the third, its choice index is 2" "Choices Followup">></nowiki></pre>
As you can see there, all the text choices lead to the same chat ("Choices Followup"). Nevertheless, that chat can change depending on what choice was made.
Here's the code of the followup:
<pre><nowiki>:: Dad Chat Choices Followup
// Store our choice index in a temporary var for quick reference
<<set _i = sp.choiceMadeIn("Choices")>>
<<send>>I'm picking the <<if _i === 0>>first<<elseif _i === 1>>second<<else>>third<</if>>, its choice index is _i.<</send>>
<<receive>>Very cool! Thanks for letting me know<</receive>>
<<tfinish>></nowiki></pre>
And that's the long and short of choice indices! The next section will cover how those can be referenced in more detail.
<hr>
<h2 id="checking-choices-access">How to Access Choices?</h2>
When accessing choices, you have three API methods you can use.
Two methods rely on a choice's ''choice index'' (covered in the previous section).
<<include "Choice Index Warning">>
The third method relies on the chat history. This is best when the choice index can't be guaranteed, or if the choice history has been disabled (more info in [[SugarPhone Settings]]).
In all cases, the text and examples come directly from the [[SugarPhone API documentation|SugarPhone API]].
<hr>
<<nobr>><h3 id="function-choice-made-in">
<nowiki>choiceMadeIn(chatKey, [contactKey=activeContactKey])</nowiki> → <em>integer</em>
</h3><</nobr>>
Returns the 0-indexed order number of a <nowiki><<textchoice>></nowiki>/<nowiki><<tchoice>></nowiki> link relative to others in the same chat.
Returns <nowiki>null</nowiki> if the chat is not part of the chat history or choice history is disabled.
<h4>Parameters:</h4>
<ul>
<li><nowiki>chatKey</nowiki>: (<i>string</i>) Suffix for some chat passage.</li>
<li><nowiki>contactKey</nowiki>: (optional, <i>string</i>) Unique key used to define the contact. If omitted and a chat is open, the active contact's key will be used.</li>
</ul>
<h4>Examples:</h4>
<b>In a chat, print choice from previous chat with active contact</b>
<pre><nowiki><<receive>>Remind me which option you chose?<</receive>>
<<send>>I chose option #<<=sp.choiceMadeIn("Some Chat")>><</send>></nowiki></pre>
<b>Check a choice made in a specified contact's chat</b>
<pre><nowiki><<receive>>What did you tell Mom?<<receive>>
<<send>> // Line breaks are ignored unless done via a <br> element
<<if sp.choiceMadeIn("Some Chat", "Mom") === 0>>
I didn't tell her anything
<<else>>
I told her everything
<</if>>
<</send>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-made-choice">
<nowiki>madeChoice(choiceIndex, chatKey, [contactKey=activeContactKey])</nowiki> → <em>boolean</em>
</h3><</nobr>>
Returns whether a specific choice was selected in a specific chat. Always returns <nowiki>false</nowiki> when choice history is disabled.
<h4>Parameters:</h4>
<ul>
<li><nowiki>choiceIndex</nowiki>: (<i>integer</i>) The 0-indexed order number of a textchoice link relative to others in the same chat.</li>
<li><nowiki>chatKey</nowiki>: (<i>string</i>) Suffix for some chat passage.</li>
<li><nowiki>contactKey</nowiki>: (optional, <i>string</i>) Unique key used to define the contact. If omitted and a chat is open, the active contact's key will be used.</li>
</ul>
<h4>Examples:</h4>
<b>Within a chat, check a previous choice with the active contact</b>
<pre><nowiki><<receive>>Did you make the first choice, way back when?<</receive>>
<<if sp.madeChoice(0, "Previous Chat")>>
<<tchoice "I did!" "Branch A">>
<<else>>
<<tchoice "I didnt :(" "Branch B">>
<</if>></nowiki></pre>
<b>Check a choice with a specified contact</b>
<pre><nowiki>"Did you make the second choice when talking to Dad?"
<<if sp.madeChoice(1, "Important Convo", "Dad")>>
"I made the second choice," you say.
<<else>>
"I made a different choice," you say. "Or I never had that conversation."
<</if>></nowiki></pre>
<hr>
<<nobr>><h3 id="function-had-chat">
<nowiki>hadChat(contactKey, ...chatKeys)</nowiki> → <em>integer</em>
</h3><</nobr>>
Returns the number of provided chats present in a contact's chat history. Ignored chats are included in this number.
<h4>Parameters:</h4>
<ul>
<li><nowiki>contactKey</nowiki>: (<i>string</i>) Unique key used to define the contact.</li>
<li><nowiki>chatKey</nowiki>: (<i>string</i> | <i>string[]</i>) Suffix for some number of possible chat passages.</li>
</ul>
<h4>Examples:</h4>
<b>Check if a single chat exists in the chat history</b>
<pre><nowiki><<if sp.hadChat("boss", "Promotion")>>
... The "Promotion" chatKey is a part of boss's chat history.
<</if>></nowiki></pre>
<b>Check if at least two chats exist in the chat history</b>
<pre><nowiki><<if sp.hadChat("boss", "Promotion", "Accept Offer", "Counter Offer") > 1>>
... At least 2 of the provided chatKeys are part of boss's chat history.
<</if>></nowiki></pre>
<hr>
<h2 id="checking-choices-summary">Summary</h2>
SugarPhone offers a number of methods to check player choices. These methods can be used both inside and out of the phone.
However, the choice index-based methods should be used cautiously. Choice indices are defined when a link appears in the chat, and so references to them are references to the links ''at the time the player saw them''.
This means links that may change number between game versions (if players are allowed to use old saves) or based on certain criteria (like relationship or money) should be considered closely.
The chat history based method, <nowiki>sp.hadChat()</nowiki>, avoids these problems while having the caveat that it only only tell you what's in the chat history, not how one got there.
Be sure to check out the full documentation for more information.
[[Home|Start]]<div class="warning"><b>WARNING:</b> Choice indices are defined when chats are loaded, and so link order cannot be guaranteed. Example: Four choices are possible, but choice #2 requires certain criteria to appear, causing choice #3 and #4 to have unreliable choice indices. Moving choice #2 to the #4 position can solve this so long as no other links have criteria.</div><h1>Group Chats</h1>
<div class="note"><b>NOTE:</b> Group chats can be simulated in regular contact chats by passing different display names to every <nowiki><<receive>></nowiki> widget. This method does not support icons, however.</div>
<h3>Index</h3>
<ul class="compact-list">
<li><a href="#group-chat-basics">Group Chat Basics</a></li>
<li><a href="#group-chat-extras">Group Chat Extras</a></li>
</ul>
<hr>
<h2 id="group-chat-basics">Group Chat Basics</h2>
Creating contact groups with SugarPhone is nearly identical to creating a regular contact. The only difference is what widget you use.
<b>Regular contact definitions</b>
<pre><nowiki><<addcontact "Mom" "Mommy" "images/mom_icon.png">>
<<addcontact "Dad">></nowiki></pre>
<b>Contact group definition with a name</b>
<pre><nowiki><<addcontactgroup "fam" "Family Chat">> // Name is optional, same as <<addcontact>></nowiki></pre>
<b>Contact group definition with a name and icon</b>
<pre><nowiki>// The icon will only appear in popups, which are disabled by default
<<addcontactgroup "fam" "Family Chat" "images/fam_icon.png">></nowiki></pre>
As you can seen, the arguments themselves behave the same and are in the same order.
Click the link below to see a group chat in action. You can click it again to reset the group chat example.
<<link "Group Chat Demo">><<removechat "fam" "Group Chat Example">><<receivechat "fam" "Group Chat Example" true>><</link>>
When you're done, let's look at that chat's code since it differs slightly from regular chats. As it says in the sample messages, every <nowiki><<receive>></nowiki> widget used in a group chat must have a valid <nowiki>contactKey</nowiki>.
<pre><nowiki>:: fam Chat Group Chat Example
<<receive "Dad">>Received messages are different in group chats.<</receive>>
<<receive "Mom">>A valid contactKey MUST be passed to each receive widget<</receive>>
<<send>>But sent messages work the same as always<</send>>
<<receive "Dad" "dadman">>You can still specify per-message names, though!<</receive>>
<<receive "Dad">>Otherwise I go back to my defined name, "Dad"<</receive>></nowiki></pre>
That's all there is to it! Choices are the same. Contact icons and names follow all the rules set in [[SugarPhone Settings]].
<div class="warning"><b>WARNING:</b> Passing an invalid <nowiki>contactKey</nowiki> (i.e. not defined yet) or no <nowiki>contactKey</nowiki> at all will result in an error. Ensure all group chat participants are defined before referencing them.</div>
<hr>
<h2 id="group-chat-extras">Group Chat Extras</h2>
<h3>Easy ContactKeys</h3>
To speed up writing group chats, you can assign <nowiki>contactKeys</nowiki> to temporary variables in a root chat. This allows the temporary variables to be referenced in all chats that follow in the chat history.
You can see the code in action with the link below, though from the player side it will be the same as if temporary variables were not used. Clicking the link will reset the example.
<div class="note"><b>NOTE:</b> When popup alerts are enabled (default: <nowiki>false</nowiki>), the previews are unable to parse these temporary variables. When using both of these features, use a string instead of a temp var for the first message of any chat that may be previewed in a popup. Enable popups in the sidebar settings and click the link to see the popup fail to parse the name.</div>
<<link "Temp Demo">><<removechat "fam" "Temp Var Example">><<receivechat "fam" "Temp Var Example" true>><</link>>
<b>Contact Definition + Add Root Chat in StoryInit</b>
<pre><nowiki><<addcontactgroup "fam" "Family Chat">>
// root is the first chat in the history
<<receivechat "fam" "root">></nowiki></pre>
<b>Root chat--it can also hold flavour text for contacts predating the game's story</b>
<pre><nowiki>:: fam Chat root
<<set _m = "Mom">><<set _d = "Dad">> // Be sure these contacts are defined already
<<receive _m>>This is some flavour text<</receive>>
<<send>>Some fun little banter!<</send>>
<<receive _d>>It helps characters feel like they existed before the start of the game<</receive>></nowiki></pre>
<b>Some chat after the root</b>
<pre><nowiki>:: fam Chat Temp Var Example
<<send>>So we can now use the temp variables here?<</send>>
<<receive _d>>Yep!<</receive>>
<<receive _d "Dadman">>And of course, I can still be "Dadman" if I want to sometimes<</receive>>
<<receive _m>>Not often, I hope<</receive>>
<<send>>Cool!<</send>>
<<tfinish>></nowiki></pre>
<h3>Styling Group Chats</h3>
<div class="note"><b>NOTE:</b> Specific styling is considered an advanced topic as you will have to write your own CSS rules. See [[Phone Structure]] for in depth information.</div>
In addition to the regular per-contact styling that the phone offers, group chats add an additional class to all received messages (those created by <nowiki><<receive>></nowiki>) so that contacts can have independent styling in group chats as well.
Here is the structure of a received message:
<pre><nowiki><div class="text-wrapper received contactKey-text">
<div class="contact-box">
<span class="contact-name">Contact Name</span>
</div>
<div class="text">Message text</div>
</div></nowiki></pre>
That means you can target all of a contact's messages in your CSS via <nowiki>#chat-int .contactKey-text</nowiki>. This applies to any group chat they are in, but not their own chat (which can be targeted via regular per-contact chat styling).<h1>Ignored Chats</h1>
This section covers how to check ignored chats and how to ignore them manually.
An ignored chat is the exact same as an inactive chat, except SugarPhone has recorded that it was ignored, allowing you to reference it later. When a live chat is ignored it also becomes inactive immediately.
Inactive chats cannot be ignored and trying to do so will cause nothing to happen.
<dv class="note"><b>NOTE:</b> When <nowiki>$phone.config.disableIgnoredChatHistory = true</nowiki> (default: <nowiki>false</nowiki>), ignored chats are NOT recorded. Ignoring live chats will still make them inactive, however.</dv>
<div class="see"><b>SEE:</b> [[Locking and Unlocking the Phone|Lock Unlock]] to prevent phone use temporarily.</div>
<h3>Index</h3>
<ul class="compact-list">
<li><a href="#checking-ignored-chats">Checking Ignored Chats</a></li>
<li><a href="#manually-ignoring-chats">Ignoring Chats</a></li>
</ul>
<hr>
<h2 id="checking-ignored-chats">Checking Ignored Chats</h2>
By default, SugarPhone ignores chats in one situation: when adding a new chat to a live conversation. It is irrelevant whether the new chat is live or not.
We can use that default situation to see ignored chats in action. Press the two buttons below in any order you like, but be sure you've pressed both before checking the phone.
<<link "Click me to add text #1">><<receivechat "Dad" "Ignore Demo 1" true>><</link>>
<<link "Click me to add text #2">><<receivechat "Dad" "Ignore Demo 2" true>><</link>>
<<link "Click me to reset">><<removechat "Dad" "Ignore Demo 1">><<removechat "Dad" "Ignore Demo 2">><</link>>
The code for those chats is identical, and only the flavour text and <nowiki>chatKeys</nowiki> differ. This is the code for chat #1:
<pre><nowiki>:: Dad Chat Ignore Demo 1
<<receive>>Hey, this is the chat for link #1.<</receive>>
<<if sp.chatIgnored() is true>>
<<receive>>I see you ignored me by clicking link #2 second :(<</receive>>
<<else>>
<<receive>>I'm glad you didn't ignore me!!<</receive>>
<</if>></nowiki></pre>
In and of itself, ignoring a chat doesn't do anything fancy. The ignored chat goes inactive, but unlike most inactive chats, the contact records that this <nowiki>chatKey</nowiki> was ignored.
The phone's methods (see: [[SugarPhone API]]) can then check the record as you see above.
When used inside the chat we wish to check, no arguments need to be passed to <nowiki>sp.chatIgnored()</nowiki>. This is because the method infers its chat location while loading into the phone.
We can also check previous chats in a contact's chat history by specifying just a <nowiki>chatKey</nowiki>. In this case, the contact alone is inferred.
<b>Check if the chat "Dad Chat Some Previous Chat" was ignored</b>
<pre><nowiki><<receive>>Hey, did you ignore some previous chat?<<receive>>
<<if sp.chatIgnored("Some Previous Chat")>>
<<receive>>It looks like you did :(<</receive>>
<<else>>
<<receive>>Looks like you didn't! Thanks for keeping up, slugger<</receive>>
<</if>></nowiki></pre>
Lastly, we can use <nowiki>sp.chatIgnored()</nowiki> outside of the phone entirely (or from another contact's chat) by specifying the <nowiki>chatKey</nowiki> and <nowiki>contactKey</nowiki>.
<b>Check if the chat "Dad Chat Ignore Demo 1" was ignored</b>
<pre><nowiki><<if sp.chatIgnored("Ignore Demo 1", "Dad")>>
The chat was ignored
<<else>>
The chat was never ignored OR the chat was never received in the first place.
<</if>></nowiki></pre>
<div class="note"><b>NOTE:</b> As with all state-based/variable checks in the phone, be sure that your <nowiki><<if>></nowiki> statements won't cause the chat history to change unexpectedly. For example, if a chat is not guaranteed to happen at a specific time, then checking if it was ignored in another chat may cause the chat history to change if/when the referenced chat is ignored.</div>
<hr>
<h2 id="manually-ignoring-chats">Ignoring Chats</h2>
By default, SugarPhone ignores chats in one situation: when adding a new chat to a live conversation. It is irrelevant whether the new chat is live or not.
In all other situations, ignoring chats is up to you.
There are two widgets that let you ignore either a specific contact's chat or ignore chats from all contacts. Trying to ignore inactive chats won't cause anything to happen, so don't worry about accidentally marking old chats as ignored.
<div class="note"><b>NOTE:</b> Only live chats can be ignored, and live chats can only be the most recent chat in a contact's chat history. As such, a <nowiki>chatKey</nowiki> never needs to be specified when ignoring chats.</div>
<h3>Ignoring All Live Chats with <nowiki><<ignoreallchats>></nowiki></h3>
<nowiki><<ignoreallchats>></nowiki> is a simple widget that, when called, ignores all live chats. This can be especially useful if your game has any day or time cycles/mechanics.
<b>Ignoring all live chats when the day rolls over</b>
<pre><nowiki><<link "Go to sleep" "Wake Up">>
<<ignoreallchats>>
<</link>></nowiki></pre>
You may also want to call this widget when entering important story events or milestones.
<h3>Ignore One Contact's Chat with <nowiki><<ignorechat>></nowiki></h3>
<nowiki><<ignorechat>></nowiki> is almost as simple as <nowiki><<ignoreallchats>></nowiki>, except in this case you must specify the contact whose chat you wish you ignore.
<pre><nowiki>// If no chat is live with "Dad", nothing will be recorded
<<ignorechat "Dad">></nowiki></pre>
See, easy! This can be great when entering character events that don't need other live chats ended or the phone to be locked.
<hr>
<h2>Summary</h2>
Ignoring chats can be a very useful feature in complicated games. At the very least, it can help to "clean up" any old messages your players may have chosen to ignore, or to give them a sort of expiry date.
If you find you never use it, however, the tracking of ignored chats can be disabled via the [[phone settings|SugarPhone Settings]]. This does ''not'' stop <nowiki><<ignorechat>></nowiki> and <nowiki><<ignoreallchats>></nowiki> from making live chats inactive, it is instead meant to limit the amount of unnecessary data being tracked.
More technical information on ignoring chats and examples can be found in the [[widget|Phone Widget Documentation]] and [[API|SugarPhone API]] documentation.
[[Home|Start]]<h1>Locking and Unlocking the Phone</h1>
There are many situations when the phone should be inaccessible to players. This may include the intro of a game, during significant events, or outside of all but a limited number of passages.
Regardless of reason, you only need two widgets: <nowiki><<lockphone>></nowiki> and <nowiki><<unlockphone>></nowiki>.
When in a locked state, the phone will not open under any circumstance, including when the <nowiki><<openphone>></nowiki> widget is used.
Below is [[documentation straight for their respective sections|Phone Widget Documentation]].
<hr>
<h3 id="widget-lock-phone"><nowiki>
<<lockphone [hide]>>
</nowiki></h3>
Closes the phone if it's open and keeps it closed until unlocked.
<nowiki><<powerbutton>></nowiki> buttons and <nowiki><<powerlink>></nowiki> links are also visually updated.
<h4>Arguments:</h4>
<ul>
<li><nowiki>hide</nowiki>: (optional) Should the phone be hidden when locked. Only applies to docked phones as un-docked phones are already hidden when closed.</li>
</ul>
<h4>Examples:</h4>
<b>Simple phone lock</b>
<pre><nowiki><<lockphone>></nowiki></pre>
<b>Phone lock and hide</b>
<pre><nowiki><<lockphone true>></nowiki></pre>
<hr>
<h3 id="widget-unlock-phone"><nowiki>
<<unlockphone>>
</nowiki></h3>
Allows the phone to be opened and the UI will return to its regular closed state.
<nowiki><<powerbutton>></nowiki> buttons and <nowiki><<powerlink>></nowiki> links will also visually update and become usable again.
<h4>Examples:</h4>
<pre><nowiki><<unlockphone>></nowiki></pre><h1>Simple CSS</h1>
Working with HTML and CSS is its own beast, and it's expected that most SugarPhone users do not want to delve deep into the phone's CSS, which can be lengthy.
Because of this, there are a few features built in to make basic customization possible. This section covers the main means of changing the phone's appearance: <b>CSS Variables</b>.
This section does not cover the CSS variables in detail, but it does provide information on the values each variable expects. When given an invalid value, a default is used.
<div class="note"><b>NOTE:</b> In general, the SugarPhone CSS does not impact the default story CSS with one exception: <nowiki>#story {padding-bottom: var(--docked-close-height, 12%)}</nowiki>. In short, that ensures the docked phone cannot obscure story content by adding padding equal to the height of the closed docked phone, which has the fallback value of 12%. You may alter/remove this rule to fit your needs, however. If using the undocked phone, for example, this rule can be removed.</div>
<div class="see"><b>SEE:</b> [[SugarPhone Settings]] for information on general chat formatting (i.e. enabling and disabling names), chat icons, and popup alerts; [[Phone Structure]] for styling that requires greater experience with HTML and CSS.</div>
<<include "Simple CSS Index">>
<hr>
<h2 id="simple-css-variable-overview">CSS Variables Overview</h2>
CSS variables are NOT SugarCube variables and, in general, you should not expect these to change during play. CSS variables are a means of creating named, reusable properties to save you the trouble of changing every single instance of a font, a color, a background, or other properties.
<div class="see"><b>SEE:</b> CSS variable information (links will open in a new tab): <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties" target="_blank">MDN Web Docs</a>; <a href="https://www.w3schools.com/css/css3_variables.asp" target="_blank">W3 Schools</a>.</div>
<hr>
<h3 id="simple-css-using-variables">Using CSS Variables</h3>
All of SugarPhone's css variables can be found at the top of its CSS attached to <nowiki>#phone-wrapper</nowiki> (in the case of all phone variables) and <nowiki>:root</nowiki> (in the case of popup alerts and <nowiki><<powerbutton>></nowiki> buttons). The former is likely the most useful.
All you need to do is change the values of those variables and the next time your game runs, the new values will be used wherever that variable is called.
You may see these at work by using your browser's inspector (right-click "Inspect") either on this demo or your project and select the <nowiki>#phone-wrapper</nowiki> element.
If you're having difficulty using the inspector, look up instructions for your specific browser. If the value you've changed a variable to isn't showing up as you expected, it may be because it is invalid or it is used primarily by animations (e.g. <nowiki>height</nowiki>) and must wait until the animation runs again (e.g. open/close).
<hr>
<h3 id="simple-css-sp-variables">SugarPhone's CSS Variables</h3>
Now let's look at SugarPhone's variables specifically. The variables are organized into the same sections and in the same order as they appear in the CSS. They appear with their full name and default value, as well as the name of the property they apply to.
Property name links will open the relevant W3 Schools page in a new tab.
<div class="warning"><b>WARNING:</b> Changing properties between relative and absolute units (see: <a href="https://www.w3schools.com/cssref/css_units.asp" target="_blank">CSS units</a>) may result in the phone becoming less friendly--or completely unusable--on different screen sizes. Test different screen sizes frequently whenever changing sizing CSS.</div>
<div class="note"><b>NOTE:</b> If you've changed a CSS variable but the current version of your game still displays the default, this may because you entered an invalid value, causing the default to be used.</div>
<<include "CSS Variable Index">>
<h4 id="phone-var-general">General Styles</h4>
Variables for the phone's general aesthetics.
<nowiki>--body-bg: #090909</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_background-color.asp" target="_blank">background-color</a>. This is the "base" color of the phone, including the text choice area.
<nowiki>--header-bg: #090909</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_background-color.asp" target="_blank">background-color</a>
<nowiki>--phone-border: 15px solid black</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_border.asp" target="_blank">border</a>
<nowiki>--phone-border-radius: 0</nowiki> -- <a href="https://www.w3schools.com/cssref/css3_pr_border-radius.asp" target="_blank">border-radius</a>
<nowiki>--phone-shadow: 10px 10px 20px 0 #b7a9a91c</nowiki> -- <a href="https://www.w3schools.com/cssref/css3_pr_box-shadow.asp" target="_blank">box-shadow</a>. Set to <nowiki>none</nowiki> to disable.
<h4 id="phone-var-sizes">Phone Sizing</h4>
Variables for the phone's dimensions. Undocked rules are not used when the phone is docked (default) and vice versa. Width rules apply to both.
<div class="see"><b>SEE:</b> Docking information [[SugarPhone Settings]].</div>
<nowiki>--docked-close-height: 12%</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_dim_height.asp" target="_blank">height</a>
<nowiki>--docked-open-height: 65%</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_dim_height.asp" target="_blank">height</a>
<nowiki>--phone-width: 80%</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_dim_width.asp" target="_blank">width</a>
<nowiki>--phone-max-width: 900px</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_dim_max-width.asp" target="_blank">max-width</a>. This takes precedence over <nowiki>--phone-width</nowiki>.
<nowiki>--undocked-open-height: 70%</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_dim_height.asp" target="_blank">height</a>
<nowiki>--undocked-top-margin: 15%</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_margin-top.asp" target="_blank">margin-top</a>. Setting this to half the size of <nowiki>--undocked-open-height</nowiki> will vertically center the phone.
<h4 id="phone-var-header">Header Styles</h4>
Variables for the phone's header.
<nowiki>--phone-header-height: 1.5em</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_dim_height.asp" target="_blank">height</a>
<nowiki>--phone-header-image-max-height: 12px</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_dim_height.asp" target="_blank">height</a>
<nowiki>--phone-header-padding: 0.2em 0 0.4em 0</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_padding.asp" target="_blank">padding</a>
<h4 id="phone-var-contact-links">Contact Link Styles</h4>
Variables for phone's contact links. When chats are live, links animate between their background color and the hover background color.
<nowiki>--contacts-bg: white</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_background-color.asp" target="_blank">background-color</a>
<nowiki>--contact-row-link: black</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_text_color.asp" target="_blank">color</a>
<nowiki>--contact-row-click-bg: #6262a1</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_background-color.asp" target="_blank">background-color</a>
<nowiki>--contact-row-hover-bg: #6262a1a3</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_background-color.asp" target="_blank">background-color</a>
<nowiki>--contact-row-bg: transparent</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_background-color.asp" target="_blank">background-color</a>
<nowiki>--contact-row-odd-bg: #79b3de70</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_background-color.asp" target="_blank">background-color</a>
<h4 id="phone-var-chats">Chat Styles</h4>
Variables for the phone's generic chat styling.
<nowiki>--chat-bg: #1a1a1a</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_background-color.asp" target="_blank">background-color</a>
<nowiki>--cb-icon-max-width: 4em</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_dim_max-width.asp" target="_blank">max-width</a>
<nowiki>--cb-text: white</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_text_color.asp" target="_blank">color</a>
<nowiki>--cb-with-icon-text: black</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_text_color.asp" target="_blank">color</a>
<nowiki>--cb-with-icon-bg: white</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_background-color.asp" target="_blank">background-color</a>
<nowiki>--cb-with-icon-border: none</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_border.asp" target="_blank">border</a>
<nowiki>--cb-with-icon-border-radius: 10px</nowiki> -- <a href="https://www.w3schools.com/cssref/css3_pr_border-radius.asp" target="_blank">border-radius</a>
<nowiki>--cb-with-icon-name-underline: 1px solid black</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_border-bottom.asp" target="_blank">border-bottom</a>
<nowiki>--loading-animation: url()</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_background-image.asp" target="_blank">background-image</a>
<nowiki>--message-border: none</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_border.asp" target="_blank">border</a>
<nowiki>--message-border-radius: 10px</nowiki> -- <a href="https://www.w3schools.com/cssref/css3_pr_border-radius.asp" target="_blank">border-radius</a>. Set to <nowiki>0</nowiki> for square messages.
<nowiki>--message-received-bg: white</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_background-color.asp" target="_blank">background-color</a>
<nowiki>--message-sent-bg: #c4def0</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_background-color.asp" target="_blank">background-color</a>
<nowiki>--message-text: black</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_text_color.asp" target="_blank">color</a>
<h4 id="phone-var-choices">Chat Choice Styles</h4>
Variables for the styling of choice and advance links in the phone. Choice link styles are also applied to the advance link. Inactive styles (applied while the chat is scrolling) apply to both.
<nowiki>--choice-link-bg: white</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_background-color.asp" target="_blank">background-color</a>
<nowiki>--choice-link-hover-bg: #dbdbdb</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_background-color.asp" target="_blank">background-color</a>
<nowiki>--choice-link-text: #68d</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_text_color.asp" target="_blank">color</a>
<nowiki>--choice-link-hover-text: #8af</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_text_color.asp" target="_blank">color</a>
<nowiki>--inactive-choice-advance-bg: lightgrey</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_background-color.asp" target="_blank">background-color</a>
<nowiki>--inactive-choice-advance-opacity: 0.5</nowiki> -- <a href="https://www.w3schools.com/cssref/css3_pr_opacity.asp" target="_blank">opacity</a>
<nowiki>--inactive-choice-advance-text: white</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_text_color.asp" target="_blank">color</a>
<nowiki>--text-choice-box-border: 1px solid #9e9e9e</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_border.asp" target="_blank">border</a>
<nowiki>--text-choice-box-border-radius: 0</nowiki> -- <a href="https://www.w3schools.com/cssref/css3_pr_border-radius.asp" target="_blank">border-radius</a>
<h4 id="phone-var-popups">Popup Styles</h4>
Variables for styling popup alerts. Popups are disabled by default.
<div class="see"><b>SEE:</b> <nowiki>$phone.config.popupAlerts</nowiki> in [[SugarPhone Settings]].</div>
<nowiki>--popup-bg: 184, 184, 255</nowiki> -- color to be used by the <a href="https://www.w3schools.com/cssref/func_rgb.asp" target="_blank">rgb()</a> function.
<nowiki>--popup-box-shadow: -1px -2px 3px #5f5f5f75</nowiki> -- <a href="https://www.w3schools.com/cssref/css3_pr_box-shadow.asp" target="_blank">box-shadow</a>. Set to <nowiki>none</nowiki> to disable.
<h4 id="phone-var-power-buttons">Power Button Styles</h4>
Variables for buttons created by <nowiki><<powerbutton>></nowiki>. The live background is only used if power button animation has been enabled.
<nowiki>--power-btn-bg: #35c</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_background-color.asp" target="_blank">background-color</a>
<nowiki>--power-btn-live-chat-bg: #213871</nowiki> -- <a href="https://www.w3schools.com/cssref/pr_background-color.asp" target="_blank">background-color</a><h3>Simple CSS</h3>
<ul class="compact-list">
<li><a href="#simple-css-variable-overview">CSS Variables Overview</a></li>
<li><a href="#simple-css-using-variables">Using CSS Variables</a></li>
<li><a href="#simple-css-sp-variables">SugarPhone's CSS Variables</a></li>
</ul><h4>CSS Variables</h4>
<ul class="compact-list">
<li><a href="#phone-var-general">General Styles</a></li>
<li><a href="#phone-var-sizes">Phone Sizing</a></li>
<li><a href="#phone-var-header">Header Styles</a></li>
<li><a href="#phone-var-contact-links">Contact Link Styles</a></li>
<li><a href="#phone-var-chats">Chat Styles</a></li>
<li><a href="#phone-var-choices">Chat Choice Styles</a></li>
<li><a href="#phone-var-popups">Popup Styles</a></li>
<li><a href="#phone-var-power-buttons">Power Button Styles</a></li>
</ul>
<hr><h1>Simple Topics</h1>
The topics in this section cover more specific information about demo content (such as choices and ignored chats), basic customization (CSS, phone header), and other topics of interest not covered by the demo (group chats, locking the phone).
<div class="note"><b>NOTE:</b> Some customization elements, such as chat icons and popup alerts, should be read about in [[SugarPhone Settings]].</div>
<<include "Simple Topics Index">><h3>Simple Topics</h3>
<ul class="compact-list">
<<if passage() != "Simple Topics">><li>[[Introduction|Simple Topics]]</li>
<</if>><<if passage() != "Adding To Phone Header">><li>[[Adding to the Phone Header|Adding To Phone Header]]</li>
<</if>><<if passage() != "Checking Choices">><li>[[Checking Choices]]</li>
<</if>><<if passage() != "Group Chats">><li>[[Group Chats]]</li>
<</if>><<if passage() != "Ignoring Chats">><li>[[Ignored Chats|Ignoring Chats]]</li>
<</if>><<if passage() != "Lock Unlock">><li>[[Locking/Unlocking the Phone|Lock Unlock]]</li>
<</if>><<if passage() != "Simple CSS">><li>[[Simple CSS]]</li><</if>>
</ul><div id="phone">
<div id="phone-header">
<div><<for _i = 0; _i < sp.getAlertCount(); _i++>><<=sp._getAlertIcon()>><</for>></div>
<div><<if Story.has("SugarPhone Head Centre")>><<include "SugarPhone Head Centre">><<else>><<powerlink>><</if>></div>
<div><<if Story.has("SugarPhone Head Right")>><<include "SugarPhone Head Right">><</if>></div>
</div>
<div id="phone-body">
<div id="text-app">
<div id="phone-contacts">
<<contactlist>>
</div>
<div id="chat">
<div id="loading"></div>
<div id="chat-int"></div>
</div>
</div>
<div id="text-choice-box-wrapper">
<div id="text-choice-box"></div>
</div>
</div>
</div><<powerlink>> |
<span class="sc-icon sc-save"><<link "Saves">><<run UI.saves()>><</link>></span> |
<span class="sc-icon sc-undo"><<link "Restart">><<run UI.restart()>><</link>></span>/* Define a textable contact */
/* SEE: <<addgroupcontact>>, <<removecontact>>, <<updatecontact>> */
/* <<addcontact contactKey [name] [iconSrc]>> */
<<widget "addcontact">>
<<if _args.length === 0>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<addcontact>></nowiki>: at least 1 argument (''contactKey'') must be passed.</span>
<<elseif !sp._contactKeyIsValid(_args[0])>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<addcontact>></nowiki>: the contactKey ''_args[0]'' cannot begin with a number, special character, or include spaces.</span>
<<elseif !sp.contactExists(_args[0])>>
<<set _contactKey = _args[0]>>
<<set _name = _args.length >= 2 ? _args[1] : _contactKey>>
<<set _icon = _args.length >= 3 ? _args[2] : "">>
<<set $phone.contacts[_contactKey] = {
alert: false,
chats: [],
choices: {},
display: true,
icon: _icon,
ignoredChats: [],
name: _name
}>>
<</if>>
<</widget>>
/* Define a textable contact group */
/* SEE: <<addcontact>>, <<removecontact>>, <<updatecontact>> */
/* <<addcontactgroup contactKey [name] [iconSrc]>> */
<<widget "addcontactgroup">>
<<if _args.length === 0>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<addcontactgroup>></nowiki>: at least 1 argument (''contactKey'') must be passed.</span>
<<elseif !sp._contactKeyIsValid(_args[0])>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<addcontactgroup>></nowiki>: the contactKey ''_args[0]'' must not begin with a number, special character, or include spaces.</span>
<<elseif !sp.contactExists(_args[0])>>
<<set _name = _args.length >= 2 ? _args[1] : _args[0]>>
<<set _icon = _args.length >= 3 ? _args[2] : "">>
<<addcontact _args[0] _name _icon>>
/* The groupChat property is the only programmatic difference between a regular contact and a contact group */
<<set sp.getContact(_args[0]).groupChat = true>>
<</if>>
<</widget>>
/* Close phone UI if it's closed, otherwise do nothing */
/* SEE: <<lockphone>>, <<openphone>>, <<togglephone>> */
/* <<closephone>> */
<<widget "closephone">>
<<run sp.closePhone()>>
<</widget>>
/* Remove all live chat flags and record ignored chats if $phone.config.disableIgnoredChatHistory = false (default: false) */
/* SEE: <<ignorechat>> */
/* <<ignoreallchats>> */
<<widget "ignoreallchats">>
<<for _contactKey range sp.getLiveContacts()>>
<<run sp.ignoreChat(_contactKey)>>
<</for>>
<</widget>>
/* Ends alerts and live chatting with a specified contact. If $phone.config.disableIgnoredChatHistory = false (default: false), the ignored chatKey will also be recorded. */
/* SEE: <<ignoreallchats>> */
/* <<ignorechat contactKey>> */
<<widget "ignorechat">>
<<if _args.length === 1>>
<<if sp.contactExists(_args[0])>>
<<run sp.ignoreChat(_args[0])>>
<<else>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<ignorechat>></nowiki>: no contact has been added with the contactKey ''_args[0]''.</span>
<</if>>
<<else>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<ignorechat>></nowiki>: expected 1 argument but ''<<= _args.length>>'' args were passed.</span>
<</if>>
<</widget>>
/* Phone is forcefully closed and open button is hidden and <<openphone>> will not function until phone is unlocked. */
/* SEE: <<unlockphone>> */
/* <<lockphone [hide]>> */
<<widget "lockphone">>
<<run sp.lock(_args[0] ? _args[0] : false)>>
<</widget>>
/* Open phone UI if it's closed, otherwise do nothing */
/* SEE: <<closephone>>, <<togglephone>> */
/* <<openphone>> */
<<widget "openphone">>
<<run sp.openPhone()>>
<</widget>>
/* Create a link that toggles the phone and displays an alert icon if there's at least one notification. Also optionally animates when at least one live chat is ongoing. */
/* SEE: <<closephone>>, <<openphone>>, <<powerlink>>, <<togglephone>> */
/* <<powerbutton [buttonText] [animateWhenLive]>> */
<<widget "powerbutton">>
<<set _allowLive = "boolean" === typeof _args[0] && _args[0] || "boolean" === typeof _args[1] && _args[1]>>
<<set _phoneBtnClass = _allowLive ? "power-btn allow-live" : "power-btn">>
/* Add animate class */
<<if _allowLive && !sp.open && sp.chatLiveWithAny()>>
<<set _phoneBtnClass += " chat-live">>
<</if>>
/* Initialize button text */
<<set _buttonText = "Toggle phone">>
<<if "string" === typeof _args[0] || "string" === typeof _args[1]>>
<<set _buttonText = "string" === typeof _args[0] ? _args[0] : _args[1]>>
<</if>>
/* Initialize power/lock icon and alert icon */
<<set _spanText = "<span class='sc-icon " + ($phone.locked ? "sc-locked" : "sc-power") +"'>" + _buttonText + "</span>">>
<<if sp.getAlertCount() > 0>>
<<set _spanText += sp._getAlertIcon()>>
<</if>>
<div @class="_phoneBtnClass"><<button _spanText>><<togglephone>><</button>></div>
<</widget>>
/* Create a link that toggles the phone and updates based on the phone's lock state */
/* SEE: <<closephone>>, <<openphone>>, <<powerbutton>>, <<togglephone>> */
/* <<powerlink [linkText]>> */
<<widget "powerlink">>
<<set _linkText = _args.length >= 1 ? _args[0] : "Power">>
<<set _powerLinkClass = $phone.locked ? "power-link phone-locked" : "power-link">>
<span @class="_powerLinkClass">
<<set _powerLinkIcon = "sc-icon sc-" + ($phone.locked ? "lock" : "power")>>
<span @class="_powerLinkIcon"><<link _linkText>><<togglephone>><</link>></span>
</span>
<</widget>>
/* A left-floated text message that displays the a contact's name, or the passed value for one-on-one chats. Use in contact group chats (defined via <<addcontactgroup>>) must specify a contactKey. */
/* SEE: <<send>> */
/* One-on-one chats: <<receive [displayName]>>...<</receive>> */
/* Group chats: <<receive contactKey [displayName]>>...<</receive>> */
<<widget "receive" container>>
<<if sp.groupChatActive && (_args.length === 0 || !sp.contactExists(_args[0]))>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<receive>></nowiki>: the chat ''<<=sp.activeContactKey>>'' (<<=sp.getName()>>) is a group chat but <<if _args.length === 0>>a contactKey was not specified for this message<<else>>the contactKey ''_args[0]'' is not defined<</if>>.</span>
<<else>>
<<set _textWrapperClass = "text-wrapper received">>
<<if sp.groupChatActive>>
<<set _contactKey = _args[0]>>
<<set _displayName = _args.length === 1 ? sp.getName(_contactKey) : _args[1]>>
<<set _icon = sp.getContact(_contactKey).icon>>
<<set sp.currentSpeaker = {key: _contactKey, name: _displayName, icon: _icon}>>
<<set _textWrapperClass += " " + _contactKey + "-text">>
<<else>>
<<set _displayName = _args.length === 0 ? sp.getName() : _args[0]>>
<<set _icon = sp.getContact().icon>>
<<set sp.currentSpeaker = {key: sp.activeContactKey, name: _displayName, icon: _icon}>>
<</if>>
<<set _nameAllowed = sp._chatNameAllowed()>> /* Should a name be displayed? */
<<set _iconAllowed = sp._chatIconAllowed()>> /* Should an icon be displayed? */
<<if $phone.config.displayChatIcons && _icon !== "">>
<<set _textWrapperClass += _iconAllowed ? " with-icon" : " after-icon">>
<</if>>
<div @class="_textWrapperClass">
/* Contact name and icon (if enabled). Repeated (sequential texts from the same contact) icons or names may be omitted based on config settings. */
<<if _nameAllowed || _iconAllowed>>
<div class="contact-box">
<<if _nameAllowed>><span class="contact-name">_displayName</span><</if>>
<<if _iconAllowed>>[img[_icon]]<</if>>
</div>
<</if>>
/* Text body */
<div class="text">
_contents
</div>
</div>
<<set sp.lastSpeaker = sp.currentSpeaker>>
<</if>>
<</widget>>
/* Use for contact-initiated conversations (i.e. a chat that starts with a <<receive>>).
Adds the specified chatKey to the chat history. Duplicates can be added by prefixing the chatKey with ##. Optional third argument marks the chat as live. */
/* SEE: <<removechat>>, <<sendchat>> */
/* <<receivechat contactKey chatKey [chatLive]>> */
<<widget "receivechat">>
<<if _args.length >= 2>>
<<set _dupe = _args[1].slice(0,2) === "##">>
<<set _contactKey = _args[0]>><<set _chatKey = _dupe ? _args[1].slice(2) : _args[1]>>
<<set _chatLive = _args[2] == true>>
<<if !sp.contactExists(_contactKey)>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<receivechat>></nowiki>: no contact exists with the contactKey ''_contactKey''.</span>
<<elseif !sp.chatPassageExists(_contactKey, _chatKey)>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<receivechat>></nowiki>: the chatKey ''_chatKey'' is not a valid key as no passage exists with the name ''<<=sp.getChatName(_contactKey, _chatKey)>>''.</span>
<<elseif _dupe || sp.hadChat(_contactKey, _chatKey) === 0>>
/* Ignore previous chatKey if chat is already live */
<<if sp.chatLiveWith(_contactKey)>>
<<run sp.ignoreChat(_contactKey)>>
<</if>>
/* Add the chat */
<<run sp._addChat(_contactKey, _chatKey, _dupe)>>
/* Set chat as live and create a text alert */
<<if _chatLive>>
<<run sp._startChatWith(_contactKey)>>
<<textalert _contactKey>>
<</if>>
<</if>>
<<else>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<receivechat>></nowiki>: 2 arguments (''contactKey'', ''chatKey'') are required and ''<<= _args.length>>'' arg(s) were passed.</span>
<</if>>
<</widget>>
/* Removes ALL instances of a specified chat from the chat history along with all of its flags. */
/* SEE: <<receivechat>>, <<sendchat>> */
/* <<removechat contactKey chatKey>> */
<<widget "removechat">>
<<if _args.length === 2>>
<<set _contactKey = _args[0]>>
<<if !sp.contactExists(_contactKey)>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<receivechat>></nowiki>: no contact exists with the contactKey ''_contactKey''.</span>
<<else>>
<<set _chatKey = _args[1]>>
<<if sp.hadChat(_contactKey, _chatKey) > 0>>
<<run sp.removeChat(_contactKey, _chatKey)>>
<</if>>
<</if>>
<<else>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<removechat>></nowiki>: 2 arguments (''contactKey'', ''chatKey'') are required and ''<<= _args.length>>'' arg(s) were passed.</span>
<</if>>
<</widget>>
/* Removes a contact and all associated information. */
/* SEE: <<addcontact>>, <<removechat>> */
/* <<removecontact contactKey>> */
<<widget "removecontact">>
<<if _args.length >= 1>>
<<set _contactKey = _args[0]>>
<<if sp.contactExists(_contactKey)>>
<<run sp.removeContact(_contactKey)>>
<</if>>
<<else>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<removecontact>></nowiki>: 1 ''contactKey'' arg must be passed.</span>
<</if>>
<</widget>>
/* A right-floated text message that displays a player's name and icon, if either are set and enabled. */
/* SEE: <<receive>> */
/* <<send [displayName]>>...<</send>> */
<<widget "send" container>>
<<set _displayName = _args.length === 0 ? $phone.config.playerName : _args[0]>>
/* currentSpeaker + lastSpeaker allow SugarPhone to handle repeated names and icons to config specs easily */
<<set sp.currentSpeaker = {key: "player", name: _displayName, icon: $phone.config.playerIcon}>>
<<set _nameAllowed = sp._chatNameAllowed()>> /* Should a name be displayed? */
<<set _iconAllowed = sp._chatIconAllowed()>> /* Should an icon be displayed? */
<<set _textWrapperClass = "text-wrapper sent">>
<<if $phone.config.displayChatIcons && $phone.config.playerIcon !== "">>
<<set _textWrapperClass += _iconAllowed ? " with-icon" : " after-icon">>
<</if>>
<div @class="_textWrapperClass">
/* Contact name and icon (if enabled). Repeated (sequential texts from the same contact) icons or names may be omitted based on config settings. */
<<if _nameAllowed || _iconAllowed>>
<div class="contact-box">
<<if _nameAllowed>><span class="contact-name">_displayName</span><</if>>
<<if _iconAllowed>>[img[$phone.config.playerIcon]]<</if>>
</div>
<</if>>
/* Text body */
<div class="text">
_contents
</div>
</div>
<<set sp.lastSpeaker = sp.currentSpeaker>>
<</widget>>
/* Use for player-initiated conversations (e.g. a chat that starts with a <<textchoice>>/<<tchoice>> or <<send>>).
Adds the specified chatKey to the chat history. Duplicates can be added by prefixing the chatKey with ##. Optional third argument marks the chat as live. */
/* SEE: <<receivechat>>, <<removechat>> */
/* <<sendchat contactKey chatKey [chatLive]>> */
<<widget "sendchat">>
<<if _args.length >= 2>>
<<set _dupe = _args[1].slice(0,2) === "##">>
<<set _contactKey = _args[0]>><<set _chatKey = _dupe ? _args[1].slice(2) : _args[1]>>
<<set _chatLive = _args[2] == true>>
<<if !sp.contactExists(_contactKey)>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<sendchat>></nowiki>: no contact exists with the contactKey ''_contactKey''.</span>
<<elseif !sp.chatPassageExists(_contactKey, _chatKey)>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<sendchat>></nowiki>: the chatKey ''_chatKey'' is not a valid key as no passage exists with the name ''<<=sp.getChatName(_contactKey, _chatKey)>>''.</span>
<<elseif _dupe || sp.hadChat(_contactKey, _chatKey) === 0>>
/* Ignore previous chatKey if chat is already live */
<<if sp.chatLiveWith(_contactKey)>>
<<run sp.ignoreChat(_contactKey)>>
<</if>>
/* Add the chat */
<<run sp._addChat(_contactKey, _chatKey, _dupe)>>
/* Set chat as live and open the phone */
<<if _chatLive>>
<<run sp._startChatWith(_contactKey)>>
<<run sp.openPhone()>>
<</if>>
<</if>>
<<else>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<sendchat>></nowiki>: 2 arguments (''contactKey'', ''chatKey'') are required and ''<<= _args.length>>'' arg(s) were passed.</span>
<</if>>
<</widget>>
/* An abbreviated alternative to <<textchoice>> that does not need a closing tag. */
/* If $phone.config.disableChoiceHistory = false (default: false), the selected link will be remembered. */
/* SEE: <<textchoice>> */
/* <<tchoice linkText chatKey>> */
<<widget "tchoice">>
<<if _args.length === 2>>
<<textchoice _args[0] _args[1]>><</textchoice>>
<<else>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<tchoice>></nowiki>: 2 arguments were expected but <<=_args.length>> arg(s) were given.</span>
<</if>>
<</widget>>
/* Creates an alert for a contact that persists until the their chat is loaded for the first time. This is regardless of whether the chat is live or not. */
/* SEE: <<receivechat>>, <<sendchat>> */
/* <<textalert contactKey>> */
<<widget "textalert">>
<<if _args.length >= 1>>
<<set sp.getContact(_args[0]).alert = true>>
/* Create a pop up alert in addition to the phone header alert */
<<if $phone.config.popupAlerts>>
/* No popup is created if the most recent chat does not contain a <<receive>> */
<<timed 0s>><<run sp._makePopupAlert(_args[0])>><</timed>>
<</if>>
<<run sp.updateAlerts()>>
<<else>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<textalert>></nowiki>: a ''contactKey'' must be specified.</span>
<</if>>
<</widget>>
/* Create a link that will continue the text conversation. */
/* If $phone.config.disableChoiceHistory = false (default: false), the selected link will be remembered. */
/* SEE: <<tchoice>> */
/* <<textchoice linkText chatKey>>...<</textchoice>> */
<<widget "textchoice" container>>
<<if _args.length === 2 && sp._inLiveChat()>>
/* Record choice ID based on link order */
<<capture _choiceID, _chatKey, _dupe>>
<<set _choiceID = sp._getChoiceID()>>
<<set _dupe = _args[1].slice(0,2) === "##">>
<<set _chatKey = _dupe ? _args[1].slice(2) : _args[1]>>
/* Create the #text-choices div if it does not exist yet */
<<if $("#text-choice-box #text-choices").length === 0>>
<<replace "#text-choice-box">><div id="text-choices"></div><</replace>>
<</if>>
/* Add the choice link to the end of #text-choices */
<<append "#text-choices">>
<<link _args[0]>>
/* Inactive while chat is scrolling */
<<if sp.clickToAdvance>>
<<silently>>_contents<</silently>>
<<run sp._makeChoice(_choiceID)>> /* Records the choice, if choice history is enabled */
<<run SugarPhone.appendChat(_chatKey, _dupe)>> /* Continue live chat into new branch */
<</if>>
<</link>>
<</append>>
<</capture>>
<<elseif _args.length < 2>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<textchoice>></nowiki>: 2 arguments were expected but <<=_args.length>> arg(s) were given.</span>
<</if>>
<</widget>>
/* Single-use link that closes the phone when clicked, optionally executing its contents. */
/* SEE: <<tfinish>> */
/* <<textfinish [linkText]>>...<</textfinish>> */
<<widget "textfinish" container>>
<<if sp._inLiveChat()>>
<<set _linkText = _args.length >= 1 ? _args[0] : "Close">>
/* Chat is considered over once .text-finish becomes visible to players even if it is not clicked */
<<replace "#text-choice-box">>
<div id="text-choices">
<span class="text-finish"><<link _linkText>>
/* Inactive while chat is scrolling */
<<if sp.clickToAdvance>>
<<silently>>_contents<</silently>>
<<run sp.closePhone()>>
<</if>>
<</link>></span>
</div>
<</replace>>
<</if>>
<</widget>>
/* An abbreviated alternative to <<textfinish>> that does not need a closing tag. */
/* SEE: <<textfinish>> */
/* <<tfinish [linkText]>> */
<<widget "tfinish">>
<<set _linkText = _args.length >= 1 ? _args[0] : "Close">>
<<textfinish _linkText>><</textfinish>>
<</widget>>
/* Toggle phone UI state between open and closed. */
/* SEE: <<closephone>>, <<openphone>> */
/* <<togglephone>> */
<<widget "togglephone">>
<<if sp.open>><<run sp.closePhone()>>
<<else>><<run sp.openPhone()>><</if>>
<</widget>>
/* Allows phones to be opened again. */
/* SEE: <<lockphone>> */
/* <<unlockphone>> */
<<widget "unlockphone">>
<<run sp.unlock()>>
<</widget>>
/* Updates alerts and state of the <<powerbutton>> and <<powerlink>> (if they exist) and the contact list (if the phone is open). */
/* <<updatealerts>> */
<<widget "updatealerts">>
<<run sp.updateAlerts()>>
<</widget>>
/* Update a select number of contact properties. Options: name, icon, display. */
/* SEE: <<addcontact>>, <<removecontact>> */
/* <<updatecontact contactKey propertyName propertyValue>> */
<<widget "updatecontact">>
<<if _args.length < 3>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<updatecontact>></nowiki>: expected 3 arguments but <<= _args.length>> arg(s) were given.</span>
<<else>>
<<set _contactKey = _args[0]>>
<<if !sp.contactExists(_contactKey)>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<updatecontact>></nowiki>: no contact exists with the contactKey ''_contactKey''.</span>
<<else>>
<<set _validProps = ["name", "icon", "display"]>>
<<set _contact = sp.getContact(_contactKey)>><<set _prop = _args[1].toLowerCase()>>
<<if _validProps.includes(_prop)>>
<<set _contact[_prop] = _args[2]>>
<<else>>
<span class="sugarphone-error">Error in SugarPhone widget <nowiki><<updatecontact>></nowiki>: the property ''_args[1]'' is not valid. Valid properties are: ''name'', ''icon'', and ''display''.</span>
<</if>>
<</if>>
<</if>>
<</widget>>
/* Updates the phone's header if custom Centre and Right content has been added. */
/* This does NOT update alerts. */
/* SEE: <<updatealerts>> */
/* <<updateheader>> */
<<widget "updateheader">>
<<run sp.updateHeader()>>
<</widget>>
/* Private Widgets */
/* Use of these widgets outside of their intended contexts will cause errors. */
/* Creates a link that will load a contact's chat when clicked. */
/* It expects to be within the #phone-contacts element when the phone is open. */
/* SEE: <<contactlist>> */
/* <<contactlink contactKey>> */
<<widget "contactlink">>
<<capture _contactKey>>
<<set _contactKey = _args[0]>>
<<set _class = "contact-row " + _contactKey + "-row">> /* Add a per-contact class */
/* Add additional class if chat is live and not open */
<<if sp.chatLiveWith(_contactKey) && sp.activeContactKey !== _contactKey>>
<<set _class += " started-chat">>
<</if>>
<div @class="_class">
<<set _linkText = sp.getName(_contactKey)>>
<<if sp.getContact(_contactKey).alert>>
<<set _linkText += sp._getAlertIcon()>>
<</if>>
<<link _linkText>>
<<run SugarPhone.loadChats(_contactKey)>>
<</link>>
</div>
<</capture>>
<</widget>>
/* Creates a list of <<contactlink>> links for displayable contacts with at least one chat in their chat history. */
/* It expects to be within the #phone-contacts element when the phone is open. */
/* SEE: <<contactlink>> */
/* <<contactlist>> */
<<widget "contactlist">>
<<for _contactKey range sp.getContactKeys()>>
<<set _contact = sp.getContact(_contactKey)>>
/* Only displays links to contacts with a chat history */
<<if _contact.chats.length && _contact.display>><<contactlink _contactKey>><</if>>
<</for>>
<</widget>><h1>SugarPhone v1.0, by LC3</h1>
SugarPhone is an interactive phone system for the SugarCube 2 (<b>v2.36+</b>) story format.
This system is intended to be usable by both novice and experienced programmers, but it will be difficult to use for anyone new to SugarCube and programming in general. It is suggested to become comfortable with SugarCube's functionality before using SugarPhone.
The SugarPhone documentation follows a similar style and format to the official SugarCube 2 documentation, but SugarPhone is NOT associated with the official development. It is a ''third-party'' resource developed by LC3/Leah Case.
This demo includes a walk through of the system, sample code, and several guides on specific topics. Links to all sections are in the sidebar. The index for your current section, if any, will also be displayed above the general index. Several phone settings can also be toggled in the sidebar at any time, though some require chat or passage reloads.
<div class="note"><b>NOTE:</b> This is the first release of SugarPhone, so there may be yet-to-be-discovered bugs and typos.</div>
<<include "Index">><h3>Introduction & Essentials</h3>
<ul class="compact-list">
<<if passage() != "Installation">><li>[[Installing SugarPhone|Installation]]</li>
<</if>><<if passage() != "Demo Start">><li>[[SugarPhone Demo|Demo Start]]</li>
<</if>><<if passage() != "SugarPhone Settings">><li>[[SugarPhone Settings]]</li>
<</if>><<if passage() != "Quick Start">><li>[[Quick Start/Code Samples|Quick Start]]</li>
<</if>><<if passage() != "Key Terms">><li>[[Key Terms]]</li><</if>>
</ul>
<h3>Documentation</h3>
<ul class="compact-list">
<<if passage() != "Phone Widget Documentation">><li>[[Widgets|Phone Widget Documentation]]</li>
<</if>><<if passage() != "SugarPhone API">><li>[[SugarPhone API|SugarPhone API]]</li>
<</if>><<if passage() != "Phone Structure">><li>[[Phone Structure (Advanced)|Phone Structure]]</li><</if>>
</ul>
<<include "Simple Topics Index">>
<<include "Advanced Topics Index">><<if passage() != "Start">>[[Home|Start]]
<</if>><<powerbutton "Power" true>>
<span id="phone-toggle-buttons"><<include "Phone Setting Toggles">></span><<if passage() === "SugarPhone API">>
<<include "SugarPhone API Index">><<elseif passage() === "Simple CSS">>
<<include "Simple CSS Index">>
<<include "CSS Variable Index">><<elseif passage() === "SugarPhone Settings">>
<<include "SugarPhone Settings Index">><<elseif passage() === "Phone Structure">>
<<include "Phone Structure Index">><<elseif passage() === "Quick Start">>
<<include "Quick Start Index">><<elseif passage() === "Key Terms">>
<<include "Key Terms Index">><<elseif passage() === "Phone Widget Documentation">>
<<include "Widget Index">><<elseif passage() === "Persistent Phone Data">>
<<include "Phone Data Index">><</if>>
<<include "Index">><h3>Phone Settings</h3><<set _p = passage()>>
<<set _settingsClass = $settingsOpen ? "open" : "">>
<<link "Hide/Show Settings">>
<<set $settingsOpen = !$settingsOpen>>
<<if $settingsOpen>>
<<addclass "#side-bar-settings" "open">>
<<else>>
<<removeclass "#side-bar-settings">>
<</if>>
<</link>><br>
<div id="side-bar-settings" @class="_settingsClass">
<<set _lockToggle = "Lock State (" + ($phone.config.locked ? "Locked" : "Unlocked") + ")">>
<<button _lockToggle>>
<<set $phone.config.locked = !$phone.config.locked>>
<<reloadtoggles>>
<</button>>
<<set _dockStateToggle = "Dock State (" + ($phone.config.docked ? "Docked" : "Un-docked") + ")">>
<<button _dockStateToggle>>
<<set $phone.config.docked = !$phone.config.docked>>
<<goto _p>>
<</button>>
<<set _chatIconToggle = "Chat Icons (" + ($phone.config.displayChatIcons ? "Enabled" : "Disabled") + ")">>
<<button _chatIconToggle>>
<<set $phone.config.displayChatIcons = !$phone.config.displayChatIcons>>
<<reloadtoggles>>
<</button>>
<<set _chatNameToggle = "Chat Names (" + ($phone.config.displayChatNames ? "Enabled" : "Disabled") + ")">>
<<button _chatNameToggle>>
<<set $phone.config.displayChatNames = !$phone.config.displayChatNames>>
<<reloadtoggles>>
<</button>>
<<set _popupToggle = "Popups (" + ($phone.config.popupAlerts ? "Enabled" : "Disabled") + ")">>
<<button _popupToggle>>
<<set $phone.config.popupAlerts = !$phone.config.popupAlerts>>
<<reloadtoggles>>
<</button>>
<<set _iconRepeatToggle = "Icon Repeat (" + ($phone.config.allowChatIconRepeat ? "Enabled" : "Disabled") + ")">>
<<button _iconRepeatToggle>>
<<set $phone.config.allowChatIconRepeat = !$phone.config.allowChatIconRepeat>>
<<reloadtoggles>>
<</button>>
<<set _nameRepeatToggle = "Name Repeat (" + ($phone.config.allowChatNameRepeat ? "Enabled" : "Disabled") + ")">>
<<button _nameRepeatToggle>>
<<set $phone.config.allowChatNameRepeat = !$phone.config.allowChatNameRepeat>>
<<reloadtoggles>>
<</button>><br>
</div><<widget "reloadtoggles">>
<<replace "#phone-toggle-buttons">><<include "Phone Setting Toggles">><</replace>>
<</widget>><<set $settingsOpen = true>>
<<set $phone = {
config: {
alertIcon: "",
allowChatIconRepeat: false,
allowChatNameRepeat: false,
chatLoadDelay: 500,
chatNameInfix: " Chat ",
chatScrollSpeed: 600,
disableChoiceHistory: false,
disableIgnoredChatHistory: false,
displayChatIcons: false,
displayChatNames: true,
docked: true,
maxLoadedChats: 25,
playerIcon: "images/player.png",
playerName: "Player",
popupAlerts: false,
pressPToToggle: true
},
contacts: {},
hide: false,
liveChats: {},
locked: false
}>>
/* All contacts are initialized with an image and a handful of inactive chats */
/* Images only display if toggled on */
<<addcontact "Dad" "Dad" "images/dad.png">>
<<receivechat "Dad" "Sample 1">>
<<receivechat "Dad" "Sample 2">>
<<receivechat "Dad" "Sample 3">>
<<addcontact "Mom" "Mommy" "images/mom.png">>
<<receivechat "Mom" "Sample 1">>
<<receivechat "Mom" "Sample 2">>
<<addcontact "friend" "Friend" "images/friend.png">>
<<receivechat "friend" "Sample 1">>
<<receivechat "friend" "Sample 2">>
<<addcontactgroup "fam" "Family Chat">>
<<receivechat "fam" "root">>
/* Used in the advanced Alternative SugarPhone Uses topic */
<<addcontact "Gallery">>
<<receivechat "Gallery" "Gallery">>
<<updatecontact "Gallery" "display" false>>
<<addcontact "reminders" "Reminders">>